From 574b503e9e87caee54c6df8143ada14268f4dcbb Mon Sep 17 00:00:00 2001 From: roridev Date: Fri, 27 Nov 2020 13:38:00 -0300 Subject: [PATCH 01/24] Moves CalculateScore function to outer scope. --- src/Discord.Net.Commands/CommandService.cs | 37 +++++++++++----------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index 1d4b0e15a..15f0c866d 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -511,7 +511,6 @@ public async Task ExecuteAsync(ICommandContext context, string input, I await _commandExecutedEvent.InvokeAsync(Optional.Create(), context, searchResult).ConfigureAwait(false); return searchResult; } - var commands = searchResult.Commands; var preconditionResults = new Dictionary(); @@ -559,24 +558,6 @@ public async Task ExecuteAsync(ICommandContext context, string input, I parseResultsDict[pair.Key] = parseResult; } - // Calculates the 'score' of a command given a parse result - float CalculateScore(CommandMatch match, ParseResult parseResult) - { - float argValuesScore = 0, paramValuesScore = 0; - - if (match.Command.Parameters.Count > 0) - { - var argValuesSum = parseResult.ArgValues?.Sum(x => x.Values.OrderByDescending(y => y.Score).FirstOrDefault().Score) ?? 0; - var paramValuesSum = parseResult.ParamValues?.Sum(x => x.Values.OrderByDescending(y => y.Score).FirstOrDefault().Score) ?? 0; - - argValuesScore = argValuesSum / match.Command.Parameters.Count; - paramValuesScore = paramValuesSum / match.Command.Parameters.Count; - } - - var totalArgsScore = (argValuesScore + paramValuesScore) / 2; - return match.Command.Priority + totalArgsScore * 0.99f; - } - //Order the parse results by their score so that we choose the most likely result to execute var parseResults = parseResultsDict .OrderByDescending(x => CalculateScore(x.Key, x.Value)); @@ -603,6 +584,24 @@ float CalculateScore(CommandMatch match, ParseResult parseResult) return result; } + // Calculates the 'score' of a command given a parse result + float CalculateScore(CommandMatch match, ParseResult parseResult) + { + float argValuesScore = 0, paramValuesScore = 0; + + if (match.Command.Parameters.Count > 0) + { + var argValuesSum = parseResult.ArgValues?.Sum(x => x.Values.OrderByDescending(y => y.Score).FirstOrDefault().Score) ?? 0; + var paramValuesSum = parseResult.ParamValues?.Sum(x => x.Values.OrderByDescending(y => y.Score).FirstOrDefault().Score) ?? 0; + + argValuesScore = argValuesSum / match.Command.Parameters.Count; + paramValuesScore = paramValuesSum / match.Command.Parameters.Count; + } + + var totalArgsScore = (argValuesScore + paramValuesScore) / 2; + return match.Command.Priority + totalArgsScore * 0.99f; + } + protected virtual void Dispose(bool disposing) { if (!_isDisposed) From 7955a0909043b964875796142bcfc5d9997e4798 Mon Sep 17 00:00:00 2001 From: roridev Date: Fri, 27 Nov 2020 13:52:53 -0300 Subject: [PATCH 02/24] Creates ValidateAndGetBestMatch function This function will validate all commands from a SearchResult and return the result of said validation, along with the command matched, if a valid match was found. --- src/Discord.Net.Commands/CommandService.cs | 77 ++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index 15f0c866d..be83b955f 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -602,6 +602,83 @@ float CalculateScore(CommandMatch match, ParseResult parseResult) return match.Command.Priority + totalArgsScore * 0.99f; } + /// + /// Validates and gets the best from a specified + /// + /// The SearchResult. + /// The context of the command. + /// The service provider to be used on the command's dependency injection. + /// The handling mode when multiple command matches are found. + /// A task that represents the asynchronous validation operation. The task result contains the result of the + /// command validation and the command matched, if a match was found. + public async Task<(IResult, Optional)> ValidateAndGetBestMatch(SearchResult matches, ICommandContext context, IServiceProvider provider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception) + { + if (!matches.IsSuccess) + return (matches, Optional.Create()); + + var commands = matches.Commands; + var preconditionResults = new Dictionary(); + + foreach (var command in commands) + { + preconditionResults[command] = await command.CheckPreconditionsAsync(context, provider); + } + + var successfulPreconditions = preconditionResults + .Where(x => x.Value.IsSuccess) + .ToArray(); + + if (successfulPreconditions.Length == 0) + { + var bestCandidate = preconditionResults + .OrderByDescending(x => x.Key.Command.Priority) + .FirstOrDefault(x => !x.Value.IsSuccess); + + return (bestCandidate.Value, bestCandidate.Key); + } + + var parseResults = new Dictionary(); + + foreach (var pair in successfulPreconditions) + { + var parseResult = await pair.Key.ParseAsync(context, matches, pair.Value, provider).ConfigureAwait(false); + + if (parseResult.Error == CommandError.MultipleMatches) + { + IReadOnlyList argList, paramList; + switch (multiMatchHandling) + { + case MultiMatchHandling.Best: + argList = parseResult.ArgValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToImmutableArray(); + paramList = parseResult.ParamValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToImmutableArray(); + parseResult = ParseResult.FromSuccess(argList, paramList); + break; + } + } + + parseResults[pair.Key] = parseResult; + } + + var weightedParseResults = parseResults + .OrderByDescending(x => CalculateScore(x.Key, x.Value)); + + var successfulParses = weightedParseResults + .Where(x => x.Value.IsSuccess) + .ToArray(); + + if(successfulParses.Length == 0) + { + var bestMatch = parseResults + .FirstOrDefault(x => !x.Value.IsSuccess); + + return (bestMatch.Value, bestMatch.Key); + } + + var chosenOverload = successfulParses[0]; + + return (chosenOverload.Value, chosenOverload.Key); + } + protected virtual void Dispose(bool disposing) { if (!_isDisposed) From c455b5033123825c639d8f18e52033b69b5595ba Mon Sep 17 00:00:00 2001 From: roridev Date: Fri, 27 Nov 2020 14:10:39 -0300 Subject: [PATCH 03/24] Make use of new ValidateAndGetBestMatch api on ExecuteAsync --- src/Discord.Net.Commands/CommandService.cs | 80 ++++------------------ 1 file changed, 12 insertions(+), 68 deletions(-) diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index be83b955f..6fbf0a9bd 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -506,82 +506,26 @@ public async Task ExecuteAsync(ICommandContext context, string input, I services = services ?? EmptyServiceProvider.Instance; var searchResult = Search(input); - if (!searchResult.IsSuccess) - { - await _commandExecutedEvent.InvokeAsync(Optional.Create(), context, searchResult).ConfigureAwait(false); - return searchResult; - } - var commands = searchResult.Commands; - var preconditionResults = new Dictionary(); - - foreach (var match in commands) - { - preconditionResults[match] = await match.Command.CheckPreconditionsAsync(context, services).ConfigureAwait(false); - } - - var successfulPreconditions = preconditionResults - .Where(x => x.Value.IsSuccess) - .ToArray(); + //Since ValidateAndGetBestMatch is deterministic on the return type, we can use pattern matching on the type for infering the code flow. + var (validationResult, commandMatch) = await ValidateAndGetBestMatch(searchResult, context, services, multiMatchHandling); - if (successfulPreconditions.Length == 0) + if(validationResult is SearchResult) { - //All preconditions failed, return the one from the highest priority command - var bestCandidate = preconditionResults - .OrderByDescending(x => x.Key.Command.Priority) - .FirstOrDefault(x => !x.Value.IsSuccess); - - await _commandExecutedEvent.InvokeAsync(bestCandidate.Key.Command, context, bestCandidate.Value).ConfigureAwait(false); - return bestCandidate.Value; + await _commandExecutedEvent.InvokeAsync(Optional.Create(), context, searchResult).ConfigureAwait(false); } - - //If we get this far, at least one precondition was successful. - - var parseResultsDict = new Dictionary(); - foreach (var pair in successfulPreconditions) + else if(validationResult is not ParseResult parseResult) { - var parseResult = await pair.Key.ParseAsync(context, searchResult, pair.Value, services).ConfigureAwait(false); - - if (parseResult.Error == CommandError.MultipleMatches) - { - IReadOnlyList argList, paramList; - switch (multiMatchHandling) - { - case MultiMatchHandling.Best: - argList = parseResult.ArgValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToImmutableArray(); - paramList = parseResult.ParamValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToImmutableArray(); - parseResult = ParseResult.FromSuccess(argList, paramList); - break; - } - } - - parseResultsDict[pair.Key] = parseResult; + await _commandExecutedEvent.InvokeAsync(commandMatch.Value.Command,context,validationResult).ConfigureAwait(false); } - - //Order the parse results by their score so that we choose the most likely result to execute - var parseResults = parseResultsDict - .OrderByDescending(x => CalculateScore(x.Key, x.Value)); - - var successfulParses = parseResults - .Where(x => x.Value.IsSuccess) - .ToArray(); - - if (successfulParses.Length == 0) + else { - //All parses failed, return the one from the highest priority command, using score as a tie breaker - var bestMatch = parseResults - .FirstOrDefault(x => !x.Value.IsSuccess); - - await _commandExecutedEvent.InvokeAsync(bestMatch.Key.Command, context, bestMatch.Value).ConfigureAwait(false); - return bestMatch.Value; + var result = await commandMatch.Value.Command.ExecuteAsync(context, parseResult, services).ConfigureAwait(false); + if (!result.IsSuccess && !(result is RuntimeResult || result is ExecuteResult)) // succesful results raise the event in CommandInfo#ExecuteInternalAsync (have to raise it there b/c deffered execution) + await _commandExecutedEvent.InvokeAsync(commandMatch.Value.Command, context, result); + return result; } - - //If we get this far, at least one parse was successful. Execute the most likely overload. - var chosenOverload = successfulParses[0]; - var result = await chosenOverload.Key.ExecuteAsync(context, chosenOverload.Value, services).ConfigureAwait(false); - if (!result.IsSuccess && !(result is RuntimeResult || result is ExecuteResult)) // succesful results raise the event in CommandInfo#ExecuteInternalAsync (have to raise it there b/c deffered execution) - await _commandExecutedEvent.InvokeAsync(chosenOverload.Key.Command, context, result); - return result; + return validationResult; } // Calculates the 'score' of a command given a parse result From 56d16397f7da77df31b6e1e2a1fd1a318c081cfd Mon Sep 17 00:00:00 2001 From: roridev Date: Fri, 27 Nov 2020 18:42:23 -0300 Subject: [PATCH 04/24] Fixes Azure linux build failing due to a CS8652. --- src/Discord.Net.Commands/CommandService.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index 6fbf0a9bd..f54072811 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -514,17 +514,17 @@ public async Task ExecuteAsync(ICommandContext context, string input, I { await _commandExecutedEvent.InvokeAsync(Optional.Create(), context, searchResult).ConfigureAwait(false); } - else if(validationResult is not ParseResult parseResult) - { - await _commandExecutedEvent.InvokeAsync(commandMatch.Value.Command,context,validationResult).ConfigureAwait(false); - } - else + else if(validationResult is ParseResult parseResult) { var result = await commandMatch.Value.Command.ExecuteAsync(context, parseResult, services).ConfigureAwait(false); if (!result.IsSuccess && !(result is RuntimeResult || result is ExecuteResult)) // succesful results raise the event in CommandInfo#ExecuteInternalAsync (have to raise it there b/c deffered execution) await _commandExecutedEvent.InvokeAsync(commandMatch.Value.Command, context, result); return result; } + else + { + await _commandExecutedEvent.InvokeAsync(commandMatch.Value.Command, context, validationResult).ConfigureAwait(false); + } return validationResult; } From 3395700720bc42b0cbb4222b9821ab40bdac54c4 Mon Sep 17 00:00:00 2001 From: Nikon <47792796+INikonI@users.noreply.github.com> Date: Mon, 23 Aug 2021 02:00:18 +0500 Subject: [PATCH 05/24] feature: IVoiceChannel implements IMentionable (#1896) --- src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs | 2 +- src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs | 5 ++++- .../Entities/Channels/SocketVoiceChannel.cs | 5 +++++ .../MockedEntities/MockedVoiceChannel.cs | 2 ++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs b/src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs index 9c2d008ee..1d36a41b9 100644 --- a/src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/IVoiceChannel.cs @@ -6,7 +6,7 @@ namespace Discord /// /// Represents a generic voice channel in a guild. /// - public interface IVoiceChannel : INestedChannel, IAudioChannel + public interface IVoiceChannel : INestedChannel, IAudioChannel, IMentionable { /// /// Gets the bit-rate that the clients in this voice channel are requested to use. diff --git a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs index 3f3aa96c6..e958f2c03 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs @@ -21,6 +21,9 @@ public class RestVoiceChannel : RestGuildChannel, IVoiceChannel, IRestAudioChann /// public ulong? CategoryId { get; private set; } + /// + public string Mention => MentionUtils.MentionChannel(Id); + internal RestVoiceChannel(BaseDiscordClient discord, IGuild guild, ulong id) : base(discord, guild, id) { @@ -60,7 +63,7 @@ public Task GetCategoryAsync(RequestOptions options = null) /// public Task SyncPermissionsAsync(RequestOptions options = null) => ChannelHelper.SyncPermissionsAsync(this, Discord, options); - + //Invites /// public async Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs index bf4a63c9f..ecaccedd3 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs @@ -20,6 +20,7 @@ public class SocketVoiceChannel : SocketGuildChannel, IVoiceChannel, ISocketAudi public int Bitrate { get; private set; } /// public int? UserLimit { get; private set; } + /// public ulong? CategoryId { get; private set; } /// @@ -30,6 +31,10 @@ public class SocketVoiceChannel : SocketGuildChannel, IVoiceChannel, ISocketAudi /// public ICategoryChannel Category => CategoryId.HasValue ? Guild.GetChannel(CategoryId.Value) as ICategoryChannel : null; + + /// + public string Mention => MentionUtils.MentionChannel(Id); + /// public Task SyncPermissionsAsync(RequestOptions options = null) => ChannelHelper.SyncPermissionsAsync(this, Discord, options); diff --git a/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs b/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs index eb617125d..6696c3613 100644 --- a/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs +++ b/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs @@ -12,6 +12,8 @@ internal sealed class MockedVoiceChannel : IVoiceChannel public int? UserLimit => throw new NotImplementedException(); + public string Mention => throw new NotImplementedException(); + public ulong? CategoryId => throw new NotImplementedException(); public int Position => throw new NotImplementedException(); From 933ea42eaac47094ef77608aa2aa3f6d602ac30d Mon Sep 17 00:00:00 2001 From: Quin Lynch <49576606+quinchs@users.noreply.github.com> Date: Tue, 23 Nov 2021 09:58:05 -0400 Subject: [PATCH 06/24] Merge Labs 3.X into dev (#1923) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * meta: bump version * Null or empty fix (#176) * Add components and stickers to ReplyAsync extension * Fixed null or empty * Changed Label to Description * -||- Co-authored-by: quin lynch * More regions (#177) * Preconditions * ChannelHelper * RestDMChannel * RestGroupChannel * RestBan * RestGroupUser * EntityExtensions * DiscordSocketClient * DiscordSocketClient * Discord.net.core.xml fix (#178) * Changed Label to Description * Added Discord- .MessageComponent .ISticker[] ,Discord.MessageComponent,Discord.ISticker[] to ReplyAsync * Remove references to labs * Update Discord.Net.sln * Added SendMessagesInThreads and StartEmbeddedActivities. (#175) * Added SendMessagesInThreads and StartEmbeddedActivities. Adjusted owner perms. Change UsePublicThreads -> CreatePublicThreads Change UsePrivateThreads -> CreatePrivateThreads * removed extra /// * Added UsePublicThreads and UsePrivateThreads back with Obsolete Attribute * removed 'false' from Obsolete Attribute * Squashed commit of the following: commit dca41a348e36a9b4e7006ef3a76377eb32aad276 Author: quin lynch Date: Thu Sep 23 07:02:19 2021 -0300 Autocomplete commands * meta: xml. closes #171 * Revert user agent and $device to dnet * meta: bump version * meta: bump vers * Fix sticker args * Grammer fix (#179) * Made IVoiceChannel mentionable * Embeds array for send message async (#181) * meta: bump version * meta: bump vers * Fix sticker args * Grammer fix (#179) * Added embeds for SendMessageAsync * [JsonProperty("embed")] forgot to remove this public Optional Embed { get; set; } * It has been done as requested. * Changed the old way of handeling single embeds * Moved embeds param and added options param * xmls Co-authored-by: quin lynch * Fix thread permissions (#183) * Update GuildPermissionsTests.cs * Update GuildPermissions.cs * Use compound assignment (#186) * Used compound assignment * -||- * -||- * Remove unnecessary suppression (#188) * Inlined variable declarations (#185) * Fixed some warnings (#184) * Fixed some warnings * Another fixed warning * Changed the SSendFileAsync to SendFileAsync * Removed para AlwaysAcknowledgeInteractions * Moved it back to the previous version * Added periods to the end like quin requested!! :(( Co-authored-by: MrCakeSlayer <13650699+MrCakeSlayer@users.noreply.github.com> * Object initialization can be simplified fixed (#189) * Conditional-expression-simplification (#193) * Capitlazation fixes (#192) * Removed-this. (#191) * Use 'switch' expression (#187) * Use 'switch' expression * Reverted it to the old switch case * Fixed-compiler-error (#194) * Submitting updates to include new permissions. (#195) * Submitting updates to include new permissions. * Make old permissions obsolete and update tests Co-authored-by: quin lynch * Update azure-pipelines.yml * Update azure-pipelines.yml * Update azure-pipelines.yml * Add support for long in autocomplete option * Add support for sending files with multiple embeds (#196) * Add support for sending files with multiple embeds * Simplify prepending single embed to embed array * Consistency for embeds endpoints (#197) * Changed the way of handling prepending of embeds. For consistency. * reformatted the summary * Revert pipeline * Fix duplicate merge conflicts * Changed minimum slash command name length to 1 per Discord API docs (#198) * Channel endpoints requirements correction (#199) * Added some requirements to channels for topic * Changed check from NotNullOrEmpty to NotNullOrEmpty * Added some requirements to channels for name Preconditions.LessThan * Formatting of file * Added restriction for description not being null (#200) * Update azure-pipelines.yml * Update deploy.yml * Remove version tag from proj * Update deploy.yml * Removed versions from project files * Removed style of the nuget badge and added logo (#201) The style was not properly added to it and the plastic version does not look good with the discord badge. I thought it would look better with a logo * Fix Type not being set in SocketApplicationCommand * Remove useless GuildId property * meta: update XML * Add Autocomplete to SlashCommandOptionBuilder * Added autocomplete in SlashCommandOptionBuilder. (#206) Co-authored-by: Quin Lynch <49576606+quinchs@users.noreply.github.com> * Fix duplicate autocomplete * Fix #208 * Fix sub commands being interpreted as a parameter for autocomplete * Fix exposed optional * Support the discord:// protocol in buttons (#207) * Update UrlValidation.cs * Update ComponentBuilder.cs * Add docs and better error messages. * Fix wonky intentation * Add competing activity status type (#205) * Update GuildPermissionsTests.cs * Update GuildPermissions.cs * Add competing status type * Add Icons to IRole (#204) * Added icon field to IRole * Added GetGuildRoleIconUrl() * Added Clean Content Function (#174) * Added Clean Content Function * Fixed Spelling problems and bad var handling * Add StripMarkDown Method * Clean Content Expanded (#212) * Implement CleanContent In IMessage & RestMessage * Update Spelling and Documentation * Add SanatizeMessage to MessageHelper and Refactor Rest and Socket Message * Add event for autocomplete interaction (#214) * Spelling corrections (#215) * Remove null collections * Followup with file async warnings (#216) * Changed from NotNullOrWhitespace to NotNullOrEmpty * Added NotNullOrEmpty on filename * Added system to interpret from the path * Added a check for if it contains a period * It has been done, how ever it will break stuff * Changed to use ??= how ever still added error check * Added space under check * Changed from with a period to valid file extension * Added checks for SendFileAsync * Removed filename != null && * Add channel types in application command options. (#217) * add channel types in application command options * Indent Docs * Stage instance audit logs as well as thread audit log type * Update azure-pipelines.yml * Update azure-pipelines.yml * Fix system messages not including mentioned users. Added ContextMenuCommand message type * Remove file extension check (#218) * Fix NRE in modify guild channel * Fix 429's not being accounted for in ratelimit updates * meta: add net5 framework Co-Authored-By: MrCakeSlayer <13650699+MrCakeSlayer@users.noreply.github.com> * Proper doc logos (#221) * Update GuildPermissionsTests.cs * Update GuildPermissions.cs * Add competing activity status type * logo changes * logo text as path * add missing logo * Update package logo and favicon * Update docfx references * Remove XML files and use original pipeline format * Remove console writeline * Remove Console.WriteLine * Remove useless log * Rename Available sticker field to IsAvailable * Rename Available to IsAvailable in stickers * Add summary indent for role members * Add summary indent to SocketInvite * Rename DefaultPermission to IsDefaultPermission * Rename Default to IsDefault and Required to IsRequired in IApplicationCommandOption * Rename Default and Required to IsDefault and IsRequired in IApplicationCommandOption. Rename DefaultPermission to IsDefaultPermission in IApplicationCommand * Remove extra white spaces * Renamed Joined, Archived, and Locked to HasJoined, IsArchived, and IsLocked * Rename Live and DiscoverableDisabled to IsDiscoverableDisabled and IsLive in IStageChannel * Remove newline * Add indent to summaries * Remove unnecessary json serializer field * Fix ToEntity for roletags incorrectly using IsPremiumSubscriber * Update RestChannel for new channel types * Fix different rest channels not deserializing properly * fully qualify internal for UrlValidation and add indent to summary * Add missing periods to InteractionResponseType * Fix summary in IApplicationCommandOptionChoice * Update IApplicationCommandOption summaries * Update IApplicationCommandInteractionDataOption summaries * Update IApplicationCommandInteractionData summaries * Update IApplicationCommand summaries * Update ApplicationCommandType summaries * rename DefaultPermission to IsDefaultPermission in ApplicationCommandProperties * update ApplicationCommandOptionChoiceProperties summaries * Rename Default, Required, and Autocomplete to IsDefault, IsRequired, and IsAutocomplete in ApplicationCommandOptionProperties * Update SlashCommandProperties summaries * update SlashCommandBuilder boolean field names, summaries, and choice parameters * Update SelectMenuOption summaries, Rename Default to IsDefault in SelectMenuOption * update SelectMenuComponent summaries. Rename Disabled to IsDisabled in SelectMenuComponent * update ComponentBuilder summaries and boolean fields. * Update ButtonComponent summaries and boolean fields * update ActionRowComponent summaries * Update UserCommandBuilder * Update MessageCommandBuilder summaries and boolean properties * Update IGuild summary * Update IGuild summaries * Update StagePrivacyLevel summary * update IThreadChannel summaries * Update IStageChannel summaries * Refactor summaries and boolean property names * General cleanup (#223) * General cleanup * Add Async suffix to SendAutocompleteResult * Fix more formatting * Fix unused RequestOptions in GetActiveThreadsAsync * Add message to ArgumentNullException * Ephemeral attachments * Add missing jsonproperty attribute * Add IMessage.Interaction * Update attachment checks for embed urls * meta: bump version * Remove old package configs and update image * Update package logos * Fix logo reference for azure * Deprecate old package definitions in favor for target file * Deprecate old package definitions in favor for target file Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update package ids * Fix url validation * meta: bump version * Fix assignment of UserMentions (#233) * Fix CleanContent (#231) * Fix SocketSlashCommandData access modifier. (#237) Fixes #229 * Update README with better header (#232) * Update README with better header Adds HTML elements that implement the main logo & improve the redirection tag positions. * Resolving border issue in light-mode * Update sponsor section * Implement checks for interaction respond times and multiple interaction responses. closes #236, #235 * Add response check to socket auto complete * meta: bump versions * Fix #239 * meta: bump version * meta: update logo * meta: bump versions * Revert received at time, confirmed by discord staff to be accurate * Merge branch 'release/3.x' of https://github.com/Discord-Net-Labs/Discord.Net-Labs into merger-labs Update requested changes of obsolete and references to labs. Added `Interaction` to `IMessage` Fixed grammar Fixed bugs relating to interactions. * Update docs * Update CHANGELOG.md * meta: docs building * Update docs.yml * Update docs.yml * Fix docfx version * Update docs.yml * Update docs.bat * Rename docs repo for clone * update docfx version * Update docs.bat * Update docfx version * Remove docs from pipeline * FAQ revamped, metadata updated (#241) * FAQ revamped, metadata updated * Update FAQ.md * Update README.md * Docs index improvement * Fix InvalidOperationException in modify channel * feature: guild avatars, closes #238 * feature: modify role icons * meta: changelog * meta: bump version * Update README.md * Fix non value type options not being included in autocomplete * Add new activity flags (#254) * Add new activity flags * Add missing commas * Added support for GUILD_JOIN_REQUEST_DELETE event (#253) Fixes #247 * Adding BotHTTPInteraction user flag (#252) * animated guild banner support (#255) * Docs work (WIP) (#242) * Main page work * Metadata logo dir * More main page edits * Naming change * Dnet guide entries pruned * Add student hub guild directory channel (#256) * animated guild banner support * Add guild directory channel * Fix followup with file overwrite having incorrect parameter locations * Merge labs 3.x * Update GUILD_JOIN_REQUEST_DELETE event * Update head.tmpl.partial * Removed BannerId and AccentColor (#260) * Removed BannerId property, GetBannerURL method, and AccentColor property from IUser and socket entities. * Fixed errors in IUser.cs * Added back summary for GetAvatarUrl method in IUser.cs * Support Guild Boost Progress Bars (#262) * Support Guild Boost Progress Bars * Update SocketChannel.cs * Fix non-optional and unnecessary values. * Spelling * Reordering and consistency. * Remove log for reconnect * Add missing flags to SystemChannelMessageDeny (#267) * Fix labs reference in analyzer project and provider project * Rename new activity flags * Guild feature revamp and smart gateway intent checks * Get thread user implementation * Amend creating slash command guide (#269) * Adding BotHTTPInteraction user flag * Added comments explaining the Global command create stipulations. * Fix numeric type check for options * Add state checking to ConnectionManager.StartAsync (#272) * initial interface changes * Multi file upload + attachment editing * meta: bump versions * Update CHANGELOG.md * Update CHANGELOG.md * Support Min and Max values on ApplicationCommandOptions (#273) * Support Min and Max values on ApplicationCommandOptions * Support decimal min/max values * Docs imrpovments + use ToNullable * Logomark, doc settings edit (#258) * Logomark, doc settings edit * Replace standard logo * Bumping docfx plugins to latest release * Bump version metadata * Logo svg fix * Change default sticker behavior and add AlwaysResolveSticker to the config * Implement rest based interactions. Added ED25519 checks. Updated summaries. * Update package logo * Automatically fix ordering of optional command options (#276) * auto fix optional command option order * clean up indentation * Fix maximum number of Select Menu Options (#282) As of https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-menu-structure the maximum number of options is 25, not less than 25. Hopefully the change catches all necessary locations * Add voice region to modify voice channels * Update summaries on rest interactions * Interaction Specific Interfaces (#283) * added interaction specific interfaces * fix build error * implement change requests * Update application * Add Guild Scheduled Events (#279) * guild events initial * sharded events * Add new gateway intents and fix bugs * More work on new changes to guild events * Update guild scheduled events * Added events to extended guild and add event start event * Update preconditions * Implement breaking changes guild guild events. Add guild event permissions * Update tests and change privacy level requirements * Update summaries and add docs for guild events * meta: bump version * Increment meta version (#285) * Increment meta version * Update docfx.json * Fix #289 and add configureawaits to rest based interactions * meta: bump version * Add GUILD_SCHEDULED_EVENT_USER_ADD and GUILD_SCHEDULED_EVENT_USER_REMOVE (#287) * Remove newline * Fix autocomplete result value * meta: bump versions * Add `GuildScheduledEventUserAdd` and `GuildScheduledEventUserRemove` to sharded client * Make RestUserCommand public (#292) * Fix Components not showing on FUWF (#288) (#293) Adds Components to Payload JSON Generation * Implement smarter rest resolvable interaction data. Fixes #294 * Add UseInteractionSnowflakeDate to config #286 * Implement Better Discord Errors (#291) * Initial error parsing * Implement better errors * Add missing error codes * Add voice disconnect opcodes * Remove unused class, add summaries to discordjsonerror, and remove public constructor of slash command properties * Add error code summary * Update error message summary * Update src/Discord.Net.Core/DiscordJsonError.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update src/Discord.Net.WebSocket/API/Voice/VoiceCloseCode.cs Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Fix autocomplete result value Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Change the minimum length of slash commands to 1 (#284) * Change the minimum length of slash commands to 1. This is the correct value according to the docs and it has been changed after user feedback. * Fix the limit in 3 other places Co-authored-by: quin lynch * Add new thread creation properties * Add role emoji. Fixes #295 * Fix mocked text channel * Fix precondition checks. Closes #281 * Initial fix (#297) * meta: bump version * Update from release/3.x * Remove more labs references * Remove doc file for Discord.Net.Analyzers Co-authored-by: Simon Hjorthøj Co-authored-by: drobbins329 Co-authored-by: MrCakeSlayer <13650699+MrCakeSlayer@users.noreply.github.com> Co-authored-by: d4n3436 Co-authored-by: Will Co-authored-by: Eugene Garbuzov Co-authored-by: CottageDwellingCat <80918250+CottageDwellingCat@users.noreply.github.com> Co-authored-by: Emily <89871431+emillly-b@users.noreply.github.com> Co-authored-by: marens101 Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> Co-authored-by: Armano den Boef <68127614+Rozen4334@users.noreply.github.com> Co-authored-by: Bill Co-authored-by: Liege72 <65319395+Liege72@users.noreply.github.com> Co-authored-by: Floowey Co-authored-by: Cenk Ergen <57065323+Cenngo@users.noreply.github.com> Co-authored-by: exsersewo Co-authored-by: Dennis Fischer --- Discord.Net.sln | 2 +- LICENSE | 2 +- README.md | 10 + docs/guides/concepts/ratelimits.md | 49 + docs/guides/emoji/emoji.md | 8 +- .../guild_events/creating-guild-events.md | 31 + .../guild_events/getting-event-users.md | 16 + docs/guides/guild_events/intro.md | 41 + docs/guides/guild_events/modifying-events.md | 23 + .../01-getting-started.md | 32 + .../creating-context-menu-commands.md | 105 + .../receiving-context-menu-command-events.md | 33 + .../02-creating-slash-commands.md | 98 + .../03-responding-to-slash-commands.md | 40 + .../slash-commands/04-parameters.md | 102 + .../05-responding-ephemerally.md | 23 + .../slash-commands/06-subcommands.md | 219 + .../slash-commands/07-choice-slash-command.md | 85 + ...bulk-overwrite-of-global-slash-commands.md | 40 + .../slash-commands/images/ephemeral1.png | Bin 0 -> 37660 bytes .../slash-commands/images/feedback1.png | Bin 0 -> 31294 bytes .../slash-commands/images/feedback2.png | Bin 0 -> 28118 bytes .../slash-commands/images/listroles1.png | Bin 0 -> 38224 bytes .../slash-commands/images/listroles2.png | Bin 0 -> 33026 bytes .../slash-commands/images/oauth.png | Bin 0 -> 113764 bytes .../slash-commands/images/settings1.png | Bin 0 -> 76171 bytes .../slash-commands/images/settings2.png | Bin 0 -> 51089 bytes .../slash-commands/images/settings3.png | Bin 0 -> 52771 bytes .../slash-commands/images/slashcommand1.png | Bin 0 -> 10886 bytes .../slash-commands/images/slashcommand2.png | Bin 0 -> 18094 bytes docs/guides/interactions/intro.md | 10 + .../message-components/01-getting-started.md | 66 + .../02-responding-to-buttons.md | 37 + .../message-components/03-buttons-in-depth.md | 45 + .../message-components/04-select-menus.md | 76 + .../message-components/05-advanced.md | 87 + .../message-components/images/image1.png | Bin 0 -> 17256 bytes .../message-components/images/image2.png | Bin 0 -> 19725 bytes .../message-components/images/image3.png | Bin 0 -> 40520 bytes .../message-components/images/image4.png | Bin 0 -> 20983 bytes .../message-components/images/image5.png | Bin 0 -> 17868 bytes .../message-components/images/image6.png | Bin 0 -> 39425 bytes docs/guides/toc.yml | 67 +- .../02_commands_framework.csproj | 2 +- .../Modules/PublicModule.cs | 2 +- samples/02_commands_framework/Program.cs | 2 +- .../03_sharded_client.csproj | 2 +- .../Services/CommandHandlingService.cs | 2 +- samples/idn/Inspector.cs | 2 +- samples/idn/Program.cs | 2 +- samples/idn/idn.csproj | 2 +- .../Discord.Net.Analyzers.csproj | 4 +- .../Attributes/AliasAttribute.cs | 2 +- .../Builders/CommandBuilder.cs | 11 +- .../Builders/ModuleBuilder.cs | 9 +- .../Builders/ModuleClassBuilder.cs | 6 +- .../Builders/ParameterBuilder.cs | 11 +- src/Discord.Net.Commands/CommandService.cs | 21 +- .../Discord.Net.Commands.csproj | 2 +- .../Extensions/MessageExtensions.cs | 3 +- src/Discord.Net.Commands/Info/CommandInfo.cs | 6 +- .../Info/ParameterInfo.cs | 4 +- src/Discord.Net.Commands/ModuleBase.cs | 13 +- src/Discord.Net.Commands/RunMode.cs | 2 +- src/Discord.Net.Core/CDN.cs | 86 +- src/Discord.Net.Core/Discord.Net.Core.csproj | 4 +- src/Discord.Net.Core/DiscordConfig.cs | 19 + src/Discord.Net.Core/DiscordErrorCode.cs | 197 + src/Discord.Net.Core/DiscordJsonError.cs | 53 + .../Entities/Activities/ActivityProperties.cs | 14 +- .../Entities/Activities/ActivityType.cs | 4 + .../Entities/ApplicationFlags.cs | 23 + .../Entities/ApplicationInstallParams.cs | 31 + .../Entities/AuditLogs/ActionType.cs | 50 + .../Entities/Channels/ChannelType.cs | 14 +- .../Entities/Channels/IMessageChannel.cs | 73 +- .../Entities/Channels/INestedChannel.cs | 46 +- .../Entities/Channels/IStageChannel.cs | 114 + .../Entities/Channels/ITextChannel.cs | 35 + .../Entities/Channels/IThreadChannel.cs | 89 + .../Channels/StageInstanceProperties.cs | 18 + .../Entities/Channels/StagePrivacyLevel.cs | 17 + .../Channels/TextChannelProperties.cs | 16 + .../Channels/ThreadArchiveDuration.cs | 34 + .../Entities/Channels/ThreadType.cs | 23 + .../Channels/VoiceChannelProperties.cs | 4 + src/Discord.Net.Core/Entities/Emotes/Emoji.cs | 5945 ++++++++++++++++- src/Discord.Net.Core/Entities/Emotes/Emote.cs | 2 + .../Entities/Guilds/GuildFeature.cs | 105 + .../Entities/Guilds/GuildFeatures.cs | 46 + .../Entities/Guilds/GuildProperties.cs | 9 +- .../Guilds/GuildScheduledEventPrivacyLevel.cs | 25 + .../Guilds/GuildScheduledEventStatus.cs | 34 + .../Guilds/GuildScheduledEventType.cs | 34 + .../Guilds/GuildScheduledEventsProperties.cs | 58 + .../Entities/Guilds/IGuild.cs | 271 +- .../Entities/Guilds/IGuildScheduledEvent.cs | 170 + .../Entities/Guilds/NsfwLevel.cs | 22 + .../Guilds/SystemChannelMessageDeny.cs | 10 +- src/Discord.Net.Core/Entities/IApplication.cs | 14 +- .../Interactions/ApplicationCommandOption.cs | 95 + .../ApplicationCommandOptionChoice.cs | 44 + .../ApplicationCommandOptionType.cs | 58 + .../ApplicationCommandProperties.cs | 22 + .../Interactions/ApplicationCommandTypes.cs | 23 + .../Interactions/AutocompleteOption.cs | 36 + .../Interactions/AutocompleteResult.cs | 73 + .../IMessageCommandInteraction.cs | 13 + .../IMessageCommandInteractionData.cs | 13 + .../ContextMenus/IUserCommandInteraction.cs | 13 + .../IUserCommandInteractionData.cs | 13 + .../ContextMenus/MessageCommandBuilder.cs | 77 + .../ContextMenus/MessageCommandProperties.cs | 10 + .../ContextMenus/UserCommandBuilder.cs | 75 + .../ContextMenus/UserCommandProperties.cs | 10 + .../Interactions/IApplicationCommand.cs | 64 + .../IApplicationCommandInteractionData.cs | 25 + ...ApplicationCommandInteractionDataOption.cs | 33 + .../Interactions/IApplicationCommandOption.cs | 60 + .../IApplicationCommandOptionChoice.cs | 18 + .../Interactions/IDiscordInteraction.cs | 90 + .../Interactions/IDiscordInteractionData.cs | 7 + .../Interactions/InteractionResponseType.cs | 46 + .../Entities/Interactions/InteractionType.cs | 28 + .../MessageComponents/ActionRowComponent.cs | 27 + .../MessageComponents/ButtonComponent.cs | 61 + .../MessageComponents/ButtonStyle.cs | 33 + .../MessageComponents/ComponentBuilder.cs | 1064 +++ .../MessageComponents/ComponentType.cs | 23 + .../IComponentInteraction.cs | 18 + .../IComponentInteractionData.cs | 25 + .../MessageComponents/IMessageComponent.cs | 18 + .../MessageComponents/MessageComponent.cs | 26 + .../MessageComponents/SelectMenuComponent.cs | 67 + .../MessageComponents/SelectMenuOption.cs | 42 + .../SlashCommands/IAutocompleteInteraction.cs | 13 + .../IAutocompleteInteractionData.cs | 40 + .../SlashCommands/ISlashCommandInteraction.cs | 13 + .../SlashCommands/SlashCommandBuilder.cs | 640 ++ .../SlashCommands/SlashCommandProperties.cs | 24 + .../Entities/Invites/TargetUserType.cs | 6 +- .../Entities/Messages/EmbedBuilder.cs | 49 +- .../Entities/Messages/FileAttachment.cs | 83 + .../Entities/Messages/IAttachment.cs | 7 + .../Entities/Messages/IMessage.cs | 26 +- .../Entities/Messages/IMessageInteraction.cs | 34 + .../Entities/Messages/MessageFlags.cs | 12 + .../Entities/Messages/MessageInteraction.cs | 45 + .../Entities/Messages/MessageProperties.cs | 26 +- .../Entities/Messages/MessageType.cs | 45 + .../Entities/Messages/StickerFormatType.cs | 25 + .../Entities/Messages/SticketFormatType.cs | 15 - .../Entities/Messages/TimestampTag.cs | 47 + .../Entities/Messages/TimestampTagStyle.cs | 43 + .../ApplicationCommandPermissionTarget.cs | 17 + .../ApplicationCommandPermissions.cs | 62 + .../Entities/Permissions/ChannelPermission.cs | 91 +- .../Permissions/ChannelPermissions.cs | 159 +- .../GuildApplicationCommandPermissions.cs | 39 + .../Entities/Permissions/GuildPermission.cs | 114 +- .../Entities/Permissions/GuildPermissions.cs | 98 +- .../Permissions/OverwritePermissions.cs | 72 +- src/Discord.Net.Core/Entities/Roles/Color.cs | 101 +- src/Discord.Net.Core/Entities/Roles/IRole.cs | 22 + .../Entities/Roles/RoleProperties.cs | 5 + .../Entities/Stickers/ICustomSticker.cs | 59 + .../{Messages => Stickers}/ISticker.cs | 36 +- .../Entities/Stickers/IStickerItem.cs | 23 + .../Entities/Stickers/StickerPack.cs | 59 + .../Entities/Stickers/StickerProperties.cs | 25 + .../Entities/Stickers/StickerType.cs | 18 + .../Entities/Users/IGuildUser.cs | 28 +- src/Discord.Net.Core/Entities/Users/IUser.cs | 13 +- .../Entities/Users/IVoiceState.cs | 6 + .../Entities/Users/UserProperties.cs | 6 +- .../Entities/Webhooks/IWebhook.cs | 7 +- .../Extensions/GuildExtensions.cs | 16 + .../Extensions/MessageExtensions.cs | 15 +- .../Extensions/ObjectExtensions.cs | 32 + .../Extensions/UserExtensions.cs | 25 +- src/Discord.Net.Core/Format.cs | 15 +- src/Discord.Net.Core/GatewayIntents.cs | 8 +- src/Discord.Net.Core/IDiscordClient.cs | 41 + .../Net/ApplicationCommandException.cs | 15 + src/Discord.Net.Core/Net/HttpException.cs | 13 +- .../Net/Rest/IRateLimitInfo.cs | 59 + src/Discord.Net.Core/RequestOptions.cs | 22 +- src/Discord.Net.Core/Utils/Cacheable.cs | 56 + src/Discord.Net.Core/Utils/MentionUtils.cs | 3 + src/Discord.Net.Core/Utils/Optional.cs | 10 +- src/Discord.Net.Core/Utils/Preconditions.cs | 12 +- src/Discord.Net.Core/Utils/UrlValidation.cs | 42 + .../Channels/IMessageChannel.Examples.cs | 1 - .../Discord.Net.Examples.csproj | 2 +- .../API/Common/ActionRowComponent.cs | 32 + .../API/Common/Application.cs | 9 +- .../API/Common/ApplicationCommand.cs | 28 + .../ApplicationCommandInteractionData.cs | 22 + ...ApplicationCommandInteractionDataOption.cs | 19 + ...plicationCommandInteractionDataResolved.cs | 22 + .../API/Common/ApplicationCommandOption.cs | 88 + .../Common/ApplicationCommandOptionChoice.cs | 13 + .../Common/ApplicationCommandPermissions.cs | 16 + src/Discord.Net.Rest/API/Common/Attachment.cs | 7 +- src/Discord.Net.Rest/API/Common/AuditLog.cs | 8 +- .../API/Common/AuditLogEntry.cs | 2 +- .../API/Common/AutocompleteInteractionData.cs | 22 + .../AutocompleteInteractionDataOption.cs | 22 + src/Discord.Net.Rest/API/Common/Ban.cs | 1 - .../API/Common/ButtonComponent.cs | 63 + src/Discord.Net.Rest/API/Common/Channel.cs | 17 +- .../API/Common/ChannelThreads.cs | 16 + src/Discord.Net.Rest/API/Common/Connection.cs | 1 - .../API/Common/DiscordError.cs | 20 + src/Discord.Net.Rest/API/Common/Embed.cs | 1 - src/Discord.Net.Rest/API/Common/EmbedImage.cs | 1 - .../API/Common/EmbedProvider.cs | 1 - .../API/Common/EmbedThumbnail.cs | 1 - src/Discord.Net.Rest/API/Common/EmbedVideo.cs | 1 - src/Discord.Net.Rest/API/Common/Emoji.cs | 1 - src/Discord.Net.Rest/API/Common/Error.cs | 12 + src/Discord.Net.Rest/API/Common/Game.cs | 3 +- src/Discord.Net.Rest/API/Common/Guild.cs | 11 +- .../GuildApplicationCommandPermissions.cs | 19 + .../API/Common/GuildMember.cs | 3 +- .../API/Common/GuildScheduledEvent.cs | 43 + .../GuildScheduledEventEntityMetadata.cs | 15 + .../API/Common/GuildScheduledEventUser.cs | 19 + .../API/Common/GuildWidget.cs | 1 - .../API/Common/InstallParams.cs | 17 + .../API/Common/Integration.cs | 1 - .../API/Common/IntegrationAccount.cs | 1 - .../API/Common/Interaction.cs | 41 + .../API/Common/InteractionCallbackData.cs | 28 + .../API/Common/InteractionResponse.cs | 13 + src/Discord.Net.Rest/API/Common/Invite.cs | 1 - .../API/Common/InviteChannel.cs | 1 - .../API/Common/InviteGuild.cs | 1 - .../API/Common/InviteMetadata.cs | 1 - .../API/Common/InviteVanity.cs | 10 + src/Discord.Net.Rest/API/Common/Message.cs | 10 +- .../Common/MessageComponentInteractionData.cs | 16 + .../API/Common/MessageInteraction.cs | 21 + .../API/Common/NitroStickerPacks.cs | 11 + src/Discord.Net.Rest/API/Common/Overwrite.cs | 1 - src/Discord.Net.Rest/API/Common/Presence.cs | 1 - .../API/Common/PropertyErrorDescription.cs | 17 + src/Discord.Net.Rest/API/Common/ReadState.cs | 1 - .../API/Common/Relationship.cs | 1 - .../API/Common/RelationshipType.cs | 1 - src/Discord.Net.Rest/API/Common/Role.cs | 5 +- src/Discord.Net.Rest/API/Common/RoleTags.cs | 1 - .../API/Common/SelectMenuComponent.cs | 42 + .../API/Common/SelectMenuOption.cs | 53 + .../API/Common/StageInstance.cs | 25 + src/Discord.Net.Rest/API/Common/Sticker.cs | 17 +- .../API/Common/StickerItem.cs | 16 + .../API/Common/StickerPack.cs | 22 + src/Discord.Net.Rest/API/Common/Team.cs | 1 - src/Discord.Net.Rest/API/Common/TeamMember.cs | 1 - .../API/Common/ThreadMember.cs | 26 + .../API/Common/ThreadMetadata.cs | 20 + src/Discord.Net.Rest/API/Common/User.cs | 5 +- src/Discord.Net.Rest/API/Common/UserGuild.cs | 1 - .../API/Common/VoiceRegion.cs | 1 - src/Discord.Net.Rest/API/Common/VoiceState.cs | 4 +- src/Discord.Net.Rest/API/Common/Webhook.cs | 3 +- src/Discord.Net.Rest/API/Int53Attribute.cs | 1 - src/Discord.Net.Rest/API/Net/IResolvable.cs | 13 + src/Discord.Net.Rest/API/Net/MultipartFile.cs | 6 +- .../Rest/CreateApplicationCommandParams.cs | 31 + .../API/Rest/CreateChannelInviteParams.cs | 7 +- .../API/Rest/CreateDMChannelParams.cs | 1 - .../API/Rest/CreateGuildBanParams.cs | 1 - .../API/Rest/CreateGuildChannelParams.cs | 1 - .../API/Rest/CreateGuildEmoteParams.cs | 1 - .../API/Rest/CreateGuildIntegrationParams.cs | 1 - .../API/Rest/CreateGuildParams.cs | 1 - .../Rest/CreateGuildScheduledEventParams.cs | 29 + .../API/Rest/CreateMessageParams.cs | 15 +- .../API/Rest/CreateStageInstanceParams.cs | 16 + .../API/Rest/CreateStickerParams.cs | 35 + .../API/Rest/CreateWebhookMessageParams.cs | 62 +- .../API/Rest/CreateWebhookParams.cs | 1 - .../API/Rest/DeleteMessagesParams.cs | 1 - .../API/Rest/GetBotGatewayResponse.cs | 1 - .../API/Rest/GetChannelMessagesParams.cs | 1 - .../API/Rest/GetEventUsersParams.cs | 15 + .../API/Rest/GetGatewayResponse.cs | 1 - .../API/Rest/GetGuildMembersParams.cs | 1 - .../API/Rest/GetGuildPruneCountResponse.cs | 1 - .../API/Rest/GetGuildSummariesParams.cs | 1 - .../API/Rest/GuildPruneParams.cs | 1 - .../Rest/ModifyApplicationCommandParams.cs | 19 + .../Rest/ModifyChannelPermissionsParams.cs | 1 - .../API/Rest/ModifyCurrentUserNickParams.cs | 1 - .../API/Rest/ModifyCurrentUserParams.cs | 1 - ...odifyGuildApplicationCommandPermissions.cs | 13 + ...uildApplicationCommandPermissionsParams.cs | 10 + .../API/Rest/ModifyGuildChannelParams.cs | 1 - .../API/Rest/ModifyGuildChannelsParams.cs | 1 - .../API/Rest/ModifyGuildEmbedParams.cs | 1 - .../API/Rest/ModifyGuildEmoteParams.cs | 1 - .../API/Rest/ModifyGuildIntegrationParams.cs | 1 - .../API/Rest/ModifyGuildMemberParams.cs | 1 - .../API/Rest/ModifyGuildParams.cs | 3 +- .../API/Rest/ModifyGuildRoleParams.cs | 3 +- .../API/Rest/ModifyGuildRolesParams.cs | 1 - .../Rest/ModifyGuildScheduledEventParams.cs | 31 + .../API/Rest/ModifyGuildWidgetParams.cs | 1 - .../Rest/ModifyInteractionResponseParams.cs | 22 + .../API/Rest/ModifyMessageParams.cs | 7 +- .../API/Rest/ModifyStageInstanceParams.cs | 13 + .../API/Rest/ModifyStickerParams.cs | 14 + .../API/Rest/ModifyTextChannelParams.cs | 1 - .../API/Rest/ModifyThreadParams.cs | 22 + .../API/Rest/ModifyVoiceChannelParams.cs | 3 +- .../API/Rest/ModifyVoiceStateParams.cs | 17 + .../API/Rest/ModifyWebhookMessageParams.cs | 3 +- .../API/Rest/ModifyWebhookParams.cs | 1 - .../API/Rest/SearchGuildMembersParams.cs | 1 - .../API/Rest/StartThreadParams.cs | 22 + .../API/Rest/UploadFileParams.cs | 54 +- .../API/Rest/UploadWebhookFileParams.cs | 1 - src/Discord.Net.Rest/BaseDiscordClient.cs | 21 +- src/Discord.Net.Rest/ClientHelper.cs | 69 +- src/Discord.Net.Rest/DiscordRestApiClient.cs | 1111 ++- src/Discord.Net.Rest/DiscordRestClient.cs | 113 +- .../Entities/AuditLogs/AuditLogHelper.cs | 3 +- .../Entities/AuditLogs/DataTypes/StageInfo.cs | 30 + .../StageInstanceCreateAuditLogData.cs | 50 + .../StageInstanceDeleteAuditLogData.cs | 50 + .../StageInstanceUpdatedAuditLogData.cs | 51 + .../Entities/Channels/ChannelHelper.cs | 151 +- .../Entities/Channels/IRestMessageChannel.cs | 21 +- .../Entities/Channels/RestCategoryChannel.cs | 5 +- .../Entities/Channels/RestChannel.cs | 61 +- .../Entities/Channels/RestDMChannel.cs | 57 +- .../Entities/Channels/RestGroupChannel.cs | 55 +- .../Entities/Channels/RestGuildChannel.cs | 48 +- .../Entities/Channels/RestStageChannel.cs | 150 + .../Entities/Channels/RestTextChannel.cs | 127 +- .../Entities/Channels/RestThreadChannel.cs | 223 + .../Entities/Channels/RestVoiceChannel.cs | 28 +- .../Entities/Channels/ThreadHelper.cs | 74 + .../Entities/Guilds/GuildHelper.cs | 382 +- .../Entities/Guilds/RestBan.cs | 5 +- .../Entities/Guilds/RestGuild.cs | 519 +- .../Entities/Guilds/RestGuildEvent.cs | 188 + .../CommandBase/RestCommandBase.cs | 345 + .../CommandBase/RestCommandBaseData.cs | 59 + .../CommandBase/RestResolvableData.cs | 96 + .../MessageCommands/RestMessageCommand.cs | 45 + .../MessageCommands/RestMessageCommandData.cs | 42 + .../UserCommands/RestUserCommand.cs | 48 + .../UserCommands/RestUserCommandData.cs | 40 + .../Interactions/InteractionHelper.cs | 542 ++ .../MessageComponents/RestMessageComponent.cs | 452 ++ .../RestMessageComponentData.cs | 37 + .../Interactions/RestApplicationCommand.cs | 77 + .../RestApplicationCommandChoice.cs | 22 + .../RestApplicationCommandOption.cs | 98 + .../Interactions/RestGlobalCommand.cs | 40 + .../Entities/Interactions/RestGuildCommand.cs | 83 + .../Entities/Interactions/RestInteraction.cs | 224 + .../Interactions/RestPingInteraction.cs | 46 + .../RestAutocompleteInteraction.cs | 135 + .../RestAutocompleteInteractionData.cs | 76 + .../SlashCommands/RestSlashCommand.cs | 48 + .../SlashCommands/RestSlashCommandData.cs | 32 + .../RestSlashCommandDataOption.cs | 139 + .../Entities/Messages/Attachment.cs | 8 +- .../Entities/Messages/CustomSticker.cs | 74 + .../Entities/Messages/MessageHelper.cs | 102 +- .../Entities/Messages/RestFollowupMessage.cs | 78 + .../Messages/RestInteractionMessage.cs | 78 + .../Entities/Messages/RestMessage.cs | 114 +- .../Entities/Messages/RestUserMessage.cs | 35 +- .../Entities/Messages/Sticker.cs | 55 +- .../Entities/Messages/StickerItem.cs | 39 + .../Entities/RestApplication.cs | 17 +- .../Entities/Roles/RestRole.cs | 25 +- .../Entities/Roles/RoleHelper.cs | 12 +- .../Entities/Users/RestGroupUser.cs | 8 +- .../Entities/Users/RestGuildUser.cs | 29 +- .../Entities/Users/RestThreadUser.cs | 56 + .../Entities/Users/RestUser.cs | 30 +- .../Entities/Users/RestWebhookUser.cs | 16 +- .../Entities/Webhooks/RestWebhook.cs | 9 +- .../Entities/Webhooks/WebhookHelper.cs | 1 - .../Extensions/EntityExtensions.cs | 3 +- .../Net/BadSignatureException.cs | 16 + .../Net/Converters/ArrayConverter.cs | 2 +- .../Net/Converters/DiscordContractResolver.cs | 17 +- .../Net/Converters/DiscordErrorConverter.cs | 88 + .../Net/Converters/EmbedTypeConverter.cs | 33 +- .../Net/Converters/GuildFeaturesConverter.cs | 60 + .../Net/Converters/InteractionConverter.cs | 70 + .../Converters/MessageComponentConverter.cs | 40 + .../Net/Converters/UnixTimestampConverter.cs | 2 +- .../Net/Converters/UserStatusConverter.cs | 24 +- src/Discord.Net.Rest/Net/DefaultRestClient.cs | 29 +- src/Discord.Net.Rest/Net/ED25519/Array16.cs | 27 + src/Discord.Net.Rest/Net/ED25519/Array8.cs | 18 + .../Net/ED25519/ByteIntegerConverter.cs | 55 + .../Net/ED25519/CryptoBytes.cs | 272 + src/Discord.Net.Rest/Net/ED25519/Ed25519.cs | 67 + .../Net/ED25519/Ed25519Operations.cs | 45 + .../Net/ED25519/Ed25519Ref10/FieldElement.cs | 23 + .../Net/ED25519/Ed25519Ref10/GroupElement.cs | 63 + .../Net/ED25519/Ed25519Ref10/base.cs | 1355 ++++ .../Net/ED25519/Ed25519Ref10/base2.cs | 50 + .../Net/ED25519/Ed25519Ref10/d.cs | 9 + .../Net/ED25519/Ed25519Ref10/d2.cs | 9 + .../Net/ED25519/Ed25519Ref10/fe_0.cs | 12 + .../Net/ED25519/Ed25519Ref10/fe_1.cs | 13 + .../Net/ED25519/Ed25519Ref10/fe_add.cs | 64 + .../Net/ED25519/Ed25519Ref10/fe_cmov.cs | 71 + .../Net/ED25519/Ed25519Ref10/fe_cswap.cs | 79 + .../Net/ED25519/Ed25519Ref10/fe_frombytes.cs | 102 + .../Net/ED25519/Ed25519Ref10/fe_invert.cs | 128 + .../Net/ED25519/Ed25519Ref10/fe_isnegative.cs | 22 + .../Net/ED25519/Ed25519Ref10/fe_isnonzero.cs | 37 + .../Net/ED25519/Ed25519Ref10/fe_mul.cs | 263 + .../Net/ED25519/Ed25519Ref10/fe_mul121666.cs | 67 + .../Net/ED25519/Ed25519Ref10/fe_neg.cs | 51 + .../Net/ED25519/Ed25519Ref10/fe_pow22523.cs | 125 + .../Net/ED25519/Ed25519Ref10/fe_sq.cs | 143 + .../Net/ED25519/Ed25519Ref10/fe_sq2.cs | 154 + .../Net/ED25519/Ed25519Ref10/fe_sub.cs | 66 + .../Net/ED25519/Ed25519Ref10/fe_tobytes.cs | 145 + .../Net/ED25519/Ed25519Ref10/ge_add.cs | 73 + .../Ed25519Ref10/ge_double_scalarmult.cs | 115 + .../Net/ED25519/Ed25519Ref10/ge_frombytes.cs | 50 + .../Net/ED25519/Ed25519Ref10/ge_madd.cs | 69 + .../Net/ED25519/Ed25519Ref10/ge_msub.cs | 68 + .../Net/ED25519/Ed25519Ref10/ge_p1p1_to_p2.cs | 18 + .../Net/ED25519/Ed25519Ref10/ge_p1p1_to_p3.cs | 18 + .../Net/ED25519/Ed25519Ref10/ge_p2_0.cs | 14 + .../Net/ED25519/Ed25519Ref10/ge_p2_dbl.cs | 64 + .../Net/ED25519/Ed25519Ref10/ge_p3_0.cs | 15 + .../Net/ED25519/Ed25519Ref10/ge_p3_dbl.cs | 17 + .../ED25519/Ed25519Ref10/ge_p3_to_cached.cs | 18 + .../Net/ED25519/Ed25519Ref10/ge_p3_to_p2.cs | 17 + .../Net/ED25519/Ed25519Ref10/ge_p3_tobytes.cs | 19 + .../Net/ED25519/Ed25519Ref10/ge_precomp_0.cs | 14 + .../Ed25519Ref10/ge_scalarmult_base.cs | 113 + .../Net/ED25519/Ed25519Ref10/ge_sub.cs | 74 + .../Net/ED25519/Ed25519Ref10/ge_tobytes.cs | 19 + .../Net/ED25519/Ed25519Ref10/keypair.cs | 23 + .../Net/ED25519/Ed25519Ref10/open.cs | 80 + .../Net/ED25519/Ed25519Ref10/sc_clamp.cs | 14 + .../Net/ED25519/Ed25519Ref10/sc_mul_add.cs | 374 ++ .../Net/ED25519/Ed25519Ref10/sc_reduce.cs | 264 + .../Net/ED25519/Ed25519Ref10/scalarmult.cs | 153 + .../Net/ED25519/Ed25519Ref10/sign.cs | 44 + .../Net/ED25519/Ed25519Ref10/sqrtm1.cs | 9 + src/Discord.Net.Rest/Net/ED25519/Sha512.cs | 155 + .../Net/ED25519/Sha512Internal.cs | 447 ++ .../Net/Queue/RequestQueueBucket.cs | 27 +- src/Discord.Net.Rest/Net/RateLimitInfo.cs | 29 +- src/Discord.Net.Rest/Utils/HexConverter.cs | 36 + .../ApplicationCommandCreatedUpdatedEvent.cs | 10 + .../API/Gateway/ExtendedGuild.cs | 12 +- .../API/Gateway/GatewayOpCode.cs | 3 +- .../API/Gateway/GuildBanEvent.cs | 1 - .../API/Gateway/GuildEmojiUpdateEvent.cs | 1 - .../Gateway/GuildJoinRequestDeleteEvent.cs | 12 + .../API/Gateway/GuildMemberAddEvent.cs | 1 - .../API/Gateway/GuildMemberRemoveEvent.cs | 1 - .../API/Gateway/GuildMemberUpdateEvent.cs | 5 +- .../API/Gateway/GuildMembersChunkEvent.cs | 1 - .../API/Gateway/GuildRoleCreateEvent.cs | 1 - .../API/Gateway/GuildRoleDeleteEvent.cs | 1 - .../API/Gateway/GuildRoleUpdateEvent.cs | 1 - .../GuildScheduledEventUserAddRemoveEvent.cs | 19 + .../API/Gateway/GuildStickerUpdateEvent.cs | 13 + .../API/Gateway/GuildSyncEvent.cs | 1 - .../API/Gateway/HelloEvent.cs | 1 - .../API/Gateway/IdentifyParams.cs | 3 +- .../API/Gateway/InviteCreatedEvent.cs | 32 + .../API/Gateway/InviteDeletedEvent.cs | 19 + .../API/Gateway/MessageDeleteBulkEvent.cs | 1 - .../API/Gateway/ReadyEvent.cs | 1 - .../API/Gateway/RecipientEvent.cs | 1 - .../API/Gateway/RequestMembersParams.cs | 1 - .../API/Gateway/ResumeParams.cs | 1 - .../API/Gateway/ResumedEvent.cs | 1 - .../API/Gateway/StatusUpdateParams.cs | 10 +- .../API/Gateway/ThreadListSyncEvent.cs | 19 + .../API/Gateway/ThreadMembersUpdate.cs | 22 + .../API/Gateway/TypingStartEvent.cs | 1 - .../API/Gateway/VoiceServerUpdateEvent.cs | 1 - .../API/Gateway/VoiceStateUpdateParams.cs | 1 - .../API/Gateway/WebhookUpdateEvent.cs | 1 - src/Discord.Net.WebSocket/API/SocketFrame.cs | 1 - .../API/Voice/IdentifyParams.cs | 1 - .../API/Voice/ReadyEvent.cs | 3 +- .../API/Voice/SelectProtocolParams.cs | 1 - .../API/Voice/SessionDescriptionEvent.cs | 1 - .../API/Voice/SpeakingEvent.cs | 1 - .../API/Voice/SpeakingParams.cs | 1 - .../API/Voice/UdpProtocolInfo.cs | 1 - .../API/Voice/VoiceCloseCode.cs | 63 + .../API/Voice/VoiceOpCode.cs | 1 - .../Audio/Streams/BufferedWriteStream.cs | 2 +- .../BaseSocketClient.Events.cs | 475 +- src/Discord.Net.WebSocket/BaseSocketClient.cs | 23 +- src/Discord.Net.WebSocket/ClientState.cs | 31 + .../Commands/ShardedCommandContext.cs | 5 +- .../Commands/SocketCommandContext.cs | 5 +- .../ConnectionManager.cs | 3 + .../Discord.Net.WebSocket.csproj | 4 +- .../DiscordShardedClient.Events.cs | 7 +- .../DiscordShardedClient.cs | 125 +- .../DiscordSocketApiClient.cs | 46 +- .../DiscordSocketClient.Events.cs | 3 +- .../DiscordSocketClient.cs | 889 ++- .../DiscordSocketConfig.cs | 31 +- .../DiscordVoiceApiClient.cs | 18 +- .../Channels/ISocketMessageChannel.cs | 19 +- .../Channels/SocketCategoryChannel.cs | 11 +- .../Entities/Channels/SocketChannel.cs | 21 +- .../Entities/Channels/SocketChannelHelper.cs | 13 +- .../Entities/Channels/SocketDMChannel.cs | 65 +- .../Entities/Channels/SocketGroupChannel.cs | 77 +- .../Entities/Channels/SocketGuildChannel.cs | 40 +- .../Entities/Channels/SocketStageChannel.cs | 158 + .../Entities/Channels/SocketTextChannel.cs | 137 +- .../Entities/Channels/SocketThreadChannel.cs | 339 + .../Entities/Channels/SocketVoiceChannel.cs | 17 +- .../Entities/Guilds/SocketGuild.cs | 668 +- .../Entities/Guilds/SocketGuildEvent.cs | 216 + .../MessageCommands/SocketMessageCommand.cs | 45 + .../SocketMessageCommandData.cs | 39 + .../UserCommands/SocketUserCommand.cs | 45 + .../UserCommands/SocketUserCommandData.cs | 39 + .../SocketMessageComponent.cs | 436 ++ .../SocketMessageComponentData.cs | 33 + .../SocketAutocompleteInteraction.cs | 126 + .../SocketAutocompleteInteractionData.cs | 73 + .../SlashCommands/SocketSlashCommand.cs | 45 + .../SlashCommands/SocketSlashCommandData.cs | 30 + .../SocketSlashCommandDataOption.cs | 135 + .../SocketApplicationCommand.cs | 116 + .../SocketApplicationCommandChoice.cs | 29 + .../SocketApplicationCommandOption.cs | 87 + .../SocketBaseCommand/SocketCommandBase.cs | 300 + .../SocketCommandBaseData.cs | 58 + .../SocketBaseCommand/SocketResolvableData.cs | 109 + .../Entities/Interaction/SocketInteraction.cs | 243 + .../Entities/Invites/SocketInvite.cs | 21 +- .../Entities/Messages/SocketMessage.cs | 130 +- .../Entities/Messages/SocketUserMessage.cs | 63 +- .../Entities/Roles/SocketRole.cs | 31 +- .../Entities/Stickers/SocketCustomSticker.cs | 81 + .../Entities/Stickers/SocketSticker.cs | 92 + .../Entities/Stickers/SocketUnknownSticker.cs | 64 + .../Entities/Users/SocketGlobalUser.cs | 2 +- .../Entities/Users/SocketGroupUser.cs | 11 +- .../Entities/Users/SocketGuildUser.cs | 19 +- .../Entities/Users/SocketThreadUser.cs | 209 + .../Entities/Users/SocketUnknownUser.cs | 3 +- .../Entities/Users/SocketVoiceState.cs | 10 +- .../Entities/Users/SocketWebhookUser.cs | 19 +- .../Extensions/EntityExtensions.cs | 21 +- .../DiscordWebhookClient.cs | 7 +- .../Messages/WebhookMessageProperties.cs | 4 + .../Entities/Webhooks/RestInternalWebhook.cs | 3 + .../WebhookClientHelper.cs | 16 +- src/Discord.Net/Discord.Net.nuspec | 2 +- .../Discord.Net.Analyzers.Tests.csproj | 6 +- .../Helpers/CodeFixVerifier.Helper.cs | 10 +- .../Helpers/DiagnosticResult.cs | 20 +- .../Helpers/DiagnosticVerifier.Helper.cs | 26 +- .../Verifiers/CodeFixVerifier.cs | 34 +- .../Verifiers/DiagnosticVerifier.cs | 42 +- .../ChannelsTests.cs | 2 +- .../Discord.Net.Tests.Integration.csproj | 4 +- .../GuildTests.cs | 2 +- .../ChannelPermissionsTests.cs | 4 + test/Discord.Net.Tests.Unit/ColorTests.cs | 3 +- .../Discord.Net.Tests.Unit.csproj | 4 +- .../EmbedBuilderTests.cs | 146 +- test/Discord.Net.Tests.Unit/FormatTests.cs | 15 + .../GuildPermissionsTests.cs | 18 +- .../MentionUtilsTests.cs | 12 +- .../MockedEntities/MockedDMChannel.cs | 21 +- .../MockedEntities/MockedGroupChannel.cs | 9 +- .../MockedEntities/MockedTextChannel.cs | 14 +- .../MockedEntities/MockedVoiceChannel.cs | 5 +- 591 files changed, 34497 insertions(+), 1560 deletions(-) create mode 100644 docs/guides/concepts/ratelimits.md create mode 100644 docs/guides/guild_events/creating-guild-events.md create mode 100644 docs/guides/guild_events/getting-event-users.md create mode 100644 docs/guides/guild_events/intro.md create mode 100644 docs/guides/guild_events/modifying-events.md create mode 100644 docs/guides/interactions/application-commands/01-getting-started.md create mode 100644 docs/guides/interactions/application-commands/context-menu-commands/creating-context-menu-commands.md create mode 100644 docs/guides/interactions/application-commands/context-menu-commands/receiving-context-menu-command-events.md create mode 100644 docs/guides/interactions/application-commands/slash-commands/02-creating-slash-commands.md create mode 100644 docs/guides/interactions/application-commands/slash-commands/03-responding-to-slash-commands.md create mode 100644 docs/guides/interactions/application-commands/slash-commands/04-parameters.md create mode 100644 docs/guides/interactions/application-commands/slash-commands/05-responding-ephemerally.md create mode 100644 docs/guides/interactions/application-commands/slash-commands/06-subcommands.md create mode 100644 docs/guides/interactions/application-commands/slash-commands/07-choice-slash-command.md create mode 100644 docs/guides/interactions/application-commands/slash-commands/08-bulk-overwrite-of-global-slash-commands.md create mode 100644 docs/guides/interactions/application-commands/slash-commands/images/ephemeral1.png create mode 100644 docs/guides/interactions/application-commands/slash-commands/images/feedback1.png create mode 100644 docs/guides/interactions/application-commands/slash-commands/images/feedback2.png create mode 100644 docs/guides/interactions/application-commands/slash-commands/images/listroles1.png create mode 100644 docs/guides/interactions/application-commands/slash-commands/images/listroles2.png create mode 100644 docs/guides/interactions/application-commands/slash-commands/images/oauth.png create mode 100644 docs/guides/interactions/application-commands/slash-commands/images/settings1.png create mode 100644 docs/guides/interactions/application-commands/slash-commands/images/settings2.png create mode 100644 docs/guides/interactions/application-commands/slash-commands/images/settings3.png create mode 100644 docs/guides/interactions/application-commands/slash-commands/images/slashcommand1.png create mode 100644 docs/guides/interactions/application-commands/slash-commands/images/slashcommand2.png create mode 100644 docs/guides/interactions/intro.md create mode 100644 docs/guides/interactions/message-components/01-getting-started.md create mode 100644 docs/guides/interactions/message-components/02-responding-to-buttons.md create mode 100644 docs/guides/interactions/message-components/03-buttons-in-depth.md create mode 100644 docs/guides/interactions/message-components/04-select-menus.md create mode 100644 docs/guides/interactions/message-components/05-advanced.md create mode 100644 docs/guides/interactions/message-components/images/image1.png create mode 100644 docs/guides/interactions/message-components/images/image2.png create mode 100644 docs/guides/interactions/message-components/images/image3.png create mode 100644 docs/guides/interactions/message-components/images/image4.png create mode 100644 docs/guides/interactions/message-components/images/image5.png create mode 100644 docs/guides/interactions/message-components/images/image6.png create mode 100644 src/Discord.Net.Core/DiscordErrorCode.cs create mode 100644 src/Discord.Net.Core/DiscordJsonError.cs create mode 100644 src/Discord.Net.Core/Entities/ApplicationFlags.cs create mode 100644 src/Discord.Net.Core/Entities/ApplicationInstallParams.cs create mode 100644 src/Discord.Net.Core/Entities/Channels/IStageChannel.cs create mode 100644 src/Discord.Net.Core/Entities/Channels/IThreadChannel.cs create mode 100644 src/Discord.Net.Core/Entities/Channels/StageInstanceProperties.cs create mode 100644 src/Discord.Net.Core/Entities/Channels/StagePrivacyLevel.cs create mode 100644 src/Discord.Net.Core/Entities/Channels/ThreadArchiveDuration.cs create mode 100644 src/Discord.Net.Core/Entities/Channels/ThreadType.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/GuildFeature.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/GuildFeatures.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/GuildScheduledEventPrivacyLevel.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/GuildScheduledEventStatus.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/GuildScheduledEventType.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/GuildScheduledEventsProperties.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/IGuildScheduledEvent.cs create mode 100644 src/Discord.Net.Core/Entities/Guilds/NsfwLevel.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionChoice.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionType.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/ApplicationCommandProperties.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/ApplicationCommandTypes.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/AutocompleteOption.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/AutocompleteResult.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/ContextMenus/IMessageCommandInteraction.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/ContextMenus/IMessageCommandInteractionData.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/ContextMenus/IUserCommandInteraction.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/ContextMenus/IUserCommandInteractionData.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/ContextMenus/MessageCommandBuilder.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/ContextMenus/MessageCommandProperties.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/ContextMenus/UserCommandBuilder.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/ContextMenus/UserCommandProperties.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/IApplicationCommandInteractionData.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/IApplicationCommandInteractionDataOption.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/IApplicationCommandOption.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/IApplicationCommandOptionChoice.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/IDiscordInteraction.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/IDiscordInteractionData.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/InteractionType.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/MessageComponents/ActionRowComponent.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/MessageComponents/ButtonComponent.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/MessageComponents/ButtonStyle.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/MessageComponents/ComponentBuilder.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/MessageComponents/ComponentType.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/MessageComponents/IComponentInteraction.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/MessageComponents/IComponentInteractionData.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/MessageComponents/IMessageComponent.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/MessageComponents/MessageComponent.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/MessageComponents/SelectMenuComponent.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/MessageComponents/SelectMenuOption.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/SlashCommands/IAutocompleteInteraction.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/SlashCommands/IAutocompleteInteractionData.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/SlashCommands/ISlashCommandInteraction.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/SlashCommands/SlashCommandBuilder.cs create mode 100644 src/Discord.Net.Core/Entities/Interactions/SlashCommands/SlashCommandProperties.cs create mode 100644 src/Discord.Net.Core/Entities/Messages/FileAttachment.cs create mode 100644 src/Discord.Net.Core/Entities/Messages/IMessageInteraction.cs create mode 100644 src/Discord.Net.Core/Entities/Messages/MessageInteraction.cs create mode 100644 src/Discord.Net.Core/Entities/Messages/StickerFormatType.cs delete mode 100644 src/Discord.Net.Core/Entities/Messages/SticketFormatType.cs create mode 100644 src/Discord.Net.Core/Entities/Messages/TimestampTag.cs create mode 100644 src/Discord.Net.Core/Entities/Messages/TimestampTagStyle.cs create mode 100644 src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissionTarget.cs create mode 100644 src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissions.cs create mode 100644 src/Discord.Net.Core/Entities/Permissions/GuildApplicationCommandPermissions.cs create mode 100644 src/Discord.Net.Core/Entities/Stickers/ICustomSticker.cs rename src/Discord.Net.Core/Entities/{Messages => Stickers}/ISticker.cs (71%) create mode 100644 src/Discord.Net.Core/Entities/Stickers/IStickerItem.cs create mode 100644 src/Discord.Net.Core/Entities/Stickers/StickerPack.cs create mode 100644 src/Discord.Net.Core/Entities/Stickers/StickerProperties.cs create mode 100644 src/Discord.Net.Core/Entities/Stickers/StickerType.cs create mode 100644 src/Discord.Net.Core/Extensions/ObjectExtensions.cs create mode 100644 src/Discord.Net.Core/Net/ApplicationCommandException.cs create mode 100644 src/Discord.Net.Core/Net/Rest/IRateLimitInfo.cs create mode 100644 src/Discord.Net.Core/Utils/UrlValidation.cs create mode 100644 src/Discord.Net.Rest/API/Common/ActionRowComponent.cs create mode 100644 src/Discord.Net.Rest/API/Common/ApplicationCommand.cs create mode 100644 src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionData.cs create mode 100644 src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionDataOption.cs create mode 100644 src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionDataResolved.cs create mode 100644 src/Discord.Net.Rest/API/Common/ApplicationCommandOption.cs create mode 100644 src/Discord.Net.Rest/API/Common/ApplicationCommandOptionChoice.cs create mode 100644 src/Discord.Net.Rest/API/Common/ApplicationCommandPermissions.cs create mode 100644 src/Discord.Net.Rest/API/Common/AutocompleteInteractionData.cs create mode 100644 src/Discord.Net.Rest/API/Common/AutocompleteInteractionDataOption.cs create mode 100644 src/Discord.Net.Rest/API/Common/ButtonComponent.cs create mode 100644 src/Discord.Net.Rest/API/Common/ChannelThreads.cs create mode 100644 src/Discord.Net.Rest/API/Common/DiscordError.cs create mode 100644 src/Discord.Net.Rest/API/Common/Error.cs create mode 100644 src/Discord.Net.Rest/API/Common/GuildApplicationCommandPermissions.cs create mode 100644 src/Discord.Net.Rest/API/Common/GuildScheduledEvent.cs create mode 100644 src/Discord.Net.Rest/API/Common/GuildScheduledEventEntityMetadata.cs create mode 100644 src/Discord.Net.Rest/API/Common/GuildScheduledEventUser.cs create mode 100644 src/Discord.Net.Rest/API/Common/InstallParams.cs create mode 100644 src/Discord.Net.Rest/API/Common/Interaction.cs create mode 100644 src/Discord.Net.Rest/API/Common/InteractionCallbackData.cs create mode 100644 src/Discord.Net.Rest/API/Common/InteractionResponse.cs create mode 100644 src/Discord.Net.Rest/API/Common/MessageComponentInteractionData.cs create mode 100644 src/Discord.Net.Rest/API/Common/MessageInteraction.cs create mode 100644 src/Discord.Net.Rest/API/Common/NitroStickerPacks.cs create mode 100644 src/Discord.Net.Rest/API/Common/PropertyErrorDescription.cs create mode 100644 src/Discord.Net.Rest/API/Common/SelectMenuComponent.cs create mode 100644 src/Discord.Net.Rest/API/Common/SelectMenuOption.cs create mode 100644 src/Discord.Net.Rest/API/Common/StageInstance.cs create mode 100644 src/Discord.Net.Rest/API/Common/StickerItem.cs create mode 100644 src/Discord.Net.Rest/API/Common/StickerPack.cs create mode 100644 src/Discord.Net.Rest/API/Common/ThreadMember.cs create mode 100644 src/Discord.Net.Rest/API/Common/ThreadMetadata.cs create mode 100644 src/Discord.Net.Rest/API/Net/IResolvable.cs create mode 100644 src/Discord.Net.Rest/API/Rest/CreateApplicationCommandParams.cs create mode 100644 src/Discord.Net.Rest/API/Rest/CreateGuildScheduledEventParams.cs create mode 100644 src/Discord.Net.Rest/API/Rest/CreateStageInstanceParams.cs create mode 100644 src/Discord.Net.Rest/API/Rest/CreateStickerParams.cs create mode 100644 src/Discord.Net.Rest/API/Rest/GetEventUsersParams.cs create mode 100644 src/Discord.Net.Rest/API/Rest/ModifyApplicationCommandParams.cs create mode 100644 src/Discord.Net.Rest/API/Rest/ModifyGuildApplicationCommandPermissions.cs create mode 100644 src/Discord.Net.Rest/API/Rest/ModifyGuildApplicationCommandPermissionsParams.cs create mode 100644 src/Discord.Net.Rest/API/Rest/ModifyGuildScheduledEventParams.cs create mode 100644 src/Discord.Net.Rest/API/Rest/ModifyInteractionResponseParams.cs create mode 100644 src/Discord.Net.Rest/API/Rest/ModifyStageInstanceParams.cs create mode 100644 src/Discord.Net.Rest/API/Rest/ModifyStickerParams.cs create mode 100644 src/Discord.Net.Rest/API/Rest/ModifyThreadParams.cs create mode 100644 src/Discord.Net.Rest/API/Rest/ModifyVoiceStateParams.cs create mode 100644 src/Discord.Net.Rest/API/Rest/StartThreadParams.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/StageInfo.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/StageInstanceCreateAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/StageInstanceDeleteAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/StageInstanceUpdatedAuditLogData.cs create mode 100644 src/Discord.Net.Rest/Entities/Channels/RestStageChannel.cs create mode 100644 src/Discord.Net.Rest/Entities/Channels/RestThreadChannel.cs create mode 100644 src/Discord.Net.Rest/Entities/Channels/ThreadHelper.cs create mode 100644 src/Discord.Net.Rest/Entities/Guilds/RestGuildEvent.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestCommandBase.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestCommandBaseData.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestResolvableData.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/MessageCommands/RestMessageCommand.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/MessageCommands/RestMessageCommandData.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/UserCommands/RestUserCommand.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/UserCommands/RestUserCommandData.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/MessageComponents/RestMessageComponent.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/MessageComponents/RestMessageComponentData.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommand.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommandChoice.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommandOption.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/RestGlobalCommand.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/RestGuildCommand.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/RestInteraction.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/RestPingInteraction.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestAutocompleteInteraction.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestAutocompleteInteractionData.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommand.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommandData.cs create mode 100644 src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommandDataOption.cs create mode 100644 src/Discord.Net.Rest/Entities/Messages/CustomSticker.cs create mode 100644 src/Discord.Net.Rest/Entities/Messages/RestFollowupMessage.cs create mode 100644 src/Discord.Net.Rest/Entities/Messages/RestInteractionMessage.cs create mode 100644 src/Discord.Net.Rest/Entities/Messages/StickerItem.cs create mode 100644 src/Discord.Net.Rest/Entities/Users/RestThreadUser.cs create mode 100644 src/Discord.Net.Rest/Net/BadSignatureException.cs create mode 100644 src/Discord.Net.Rest/Net/Converters/DiscordErrorConverter.cs create mode 100644 src/Discord.Net.Rest/Net/Converters/GuildFeaturesConverter.cs create mode 100644 src/Discord.Net.Rest/Net/Converters/InteractionConverter.cs create mode 100644 src/Discord.Net.Rest/Net/Converters/MessageComponentConverter.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Array16.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Array8.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/ByteIntegerConverter.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/CryptoBytes.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Operations.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/FieldElement.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/GroupElement.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/base.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/base2.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/d.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/d2.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_0.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_1.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_add.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_cmov.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_cswap.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_frombytes.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_invert.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_isnegative.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_isnonzero.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_mul.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_mul121666.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_neg.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_pow22523.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_sq.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_sq2.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_sub.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_tobytes.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_add.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_double_scalarmult.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_frombytes.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_madd.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_msub.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_p1p1_to_p2.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_p1p1_to_p3.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_p2_0.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_p2_dbl.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_p3_0.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_p3_dbl.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_p3_to_cached.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_p3_to_p2.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_p3_tobytes.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_precomp_0.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_scalarmult_base.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_sub.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_tobytes.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/keypair.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/open.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/sc_clamp.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/sc_mul_add.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/sc_reduce.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/scalarmult.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/sign.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/sqrtm1.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Sha512.cs create mode 100644 src/Discord.Net.Rest/Net/ED25519/Sha512Internal.cs create mode 100644 src/Discord.Net.Rest/Utils/HexConverter.cs create mode 100644 src/Discord.Net.WebSocket/API/Gateway/ApplicationCommandCreatedUpdatedEvent.cs create mode 100644 src/Discord.Net.WebSocket/API/Gateway/GuildJoinRequestDeleteEvent.cs create mode 100644 src/Discord.Net.WebSocket/API/Gateway/GuildScheduledEventUserAddRemoveEvent.cs create mode 100644 src/Discord.Net.WebSocket/API/Gateway/GuildStickerUpdateEvent.cs create mode 100644 src/Discord.Net.WebSocket/API/Gateway/InviteCreatedEvent.cs create mode 100644 src/Discord.Net.WebSocket/API/Gateway/InviteDeletedEvent.cs create mode 100644 src/Discord.Net.WebSocket/API/Gateway/ThreadListSyncEvent.cs create mode 100644 src/Discord.Net.WebSocket/API/Gateway/ThreadMembersUpdate.cs create mode 100644 src/Discord.Net.WebSocket/API/Voice/VoiceCloseCode.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Channels/SocketStageChannel.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Channels/SocketThreadChannel.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Guilds/SocketGuildEvent.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/ContextMenuCommands/MessageCommands/SocketMessageCommand.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/ContextMenuCommands/MessageCommands/SocketMessageCommandData.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/ContextMenuCommands/UserCommands/SocketUserCommand.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/ContextMenuCommands/UserCommands/SocketUserCommandData.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/MessageComponents/SocketMessageComponent.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/MessageComponents/SocketMessageComponentData.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketAutocompleteInteraction.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketAutocompleteInteractionData.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketSlashCommand.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketSlashCommandData.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketSlashCommandDataOption.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommand.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommandChoice.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommandOption.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketCommandBase.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketCommandBaseData.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketResolvableData.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Stickers/SocketCustomSticker.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Stickers/SocketSticker.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Stickers/SocketUnknownSticker.cs create mode 100644 src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs diff --git a/Discord.Net.sln b/Discord.Net.sln index 1a32f1270..084d8a834 100644 --- a/Discord.Net.sln +++ b/Discord.Net.sln @@ -40,7 +40,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Analyzers.Tests EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Examples", "src\Discord.Net.Examples\Discord.Net.Examples.csproj", "{47820065-3CFB-401C-ACEA-862BD564A404}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "idn", "samples\idn\idn.csproj", "{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "idn", "samples\idn\idn.csproj", "{4A03840B-9EBE-47E3-89AB-E0914DF21AFB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/LICENSE b/LICENSE index 3765bf39c..fb9480169 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015-2019 Discord.Net Contributors +Copyright (c) 2015-2021 Discord.Net Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 32e1515af..87b46fb64 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Discord.Net + [![NuGet](https://img.shields.io/nuget/vpre/Discord.Net.svg?maxAge=2592000?style=plastic)](https://www.nuget.org/packages/Discord.Net) [![MyGet](https://img.shields.io/myget/discord-net/vpre/Discord.Net.svg)](https://www.myget.org/feed/Packages/discord-net) [![Build Status](https://dev.azure.com/discord-net/Discord.Net/_apis/build/status/discord-net.Discord.Net?branchName=dev)](https://dev.azure.com/discord-net/Discord.Net/_build/latest?definitionId=1&branchName=dev) @@ -12,34 +13,43 @@ An unofficial .NET API Wrapper for the Discord client (https://discord.com). - [Latest CI repo](https://github.com/discord-net/docs-static) ## Installation + ### Stable (NuGet) + Our stable builds available from NuGet through the Discord.Net metapackage: + - [Discord.Net](https://www.nuget.org/packages/Discord.Net/) The individual components may also be installed from NuGet: + - [Discord.Net.Commands](https://www.nuget.org/packages/Discord.Net.Commands/) - [Discord.Net.Rest](https://www.nuget.org/packages/Discord.Net.Rest/) - [Discord.Net.WebSocket](https://www.nuget.org/packages/Discord.Net.WebSocket/) - [Discord.Net.Webhook](https://www.nuget.org/packages/Discord.Net.Webhook/) ### Unstable (MyGet) + Nightly builds are available through our MyGet feed (`https://www.myget.org/F/discord-net/api/v3/index.json`). ## Compiling + In order to compile Discord.Net, you require the following: ### Using Visual Studio + - [Visual Studio 2017](https://www.microsoft.com/net/core#windowsvs2017) - [.NET Core SDK](https://www.microsoft.com/net/download/core) The .NET Core workload must be selected during Visual Studio installation. ### Using Command Line + - [.NET Core SDK](https://www.microsoft.com/net/download/core) ## Known Issues ### WebSockets (Win7 and earlier) + .NET Core 1.1 does not support WebSockets on Win7 and earlier. This issue has been fixed since the release of .NET Core 2.1. It is recommended to target .NET Core 2.1 or above for your project if you wish to run your bot on legacy platforms; alternatively, you may choose to install the [Discord.Net.Providers.WS4Net](https://www.nuget.org/packages/Discord.Net.Providers.WS4Net/) package. ## Versioning Guarantees diff --git a/docs/guides/concepts/ratelimits.md b/docs/guides/concepts/ratelimits.md new file mode 100644 index 000000000..afeb5f795 --- /dev/null +++ b/docs/guides/concepts/ratelimits.md @@ -0,0 +1,49 @@ +# Ratelimits + +Ratelimits are a core concept of any API - Discords API is no exception. each verified library must follow the ratelimit guidelines. + +### Using the ratelimit callback + +There is a new property within `RequestOptions` called RatelimitCallback. This callback is called when a request is made via the rest api. The callback is called with a `IRateLimitInfo` parameter: + +| Name | Type | Description | +| ---------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| IsGlobal | bool | Whether or not this ratelimit info is global. | +| Limit | int? | The number of requests that can be made. | +| Remaining | int? | The number of remaining requests that can be made. | +| RetryAfter | int? | The total time (in seconds) of when the current rate limit bucket will reset. Can have decimals to match previous millisecond ratelimit precision. | +| Reset | DateTimeOffset? | The time at which the rate limit resets. | +| ResetAfter | TimeSpan? | The absolute time when this ratelimit resets. | +| Bucket | string | A unique string denoting the rate limit being encountered (non-inclusive of major parameters in the route path). | +| Lag | TimeSpan? | The amount of lag for the request. This is used to denote the precise time of when the ratelimit expires. | +| Endpoint | string | The endpoint that this ratelimit info came from. | + +Let's set up a ratelimit callback that will print out the ratelimit info to the console. + +```cs +public async Task MyRatelimitCallback(IRateLimitInfo info) +{ + Console.WriteLine($"{info.IsGlobal} {info.Limit} {info.Remaining} {info.RetryAfter} {info.Reset} {info.ResetAfter} {info.Bucket} {info.Lag} {info.Endpoint}"); +} +``` + +Let's use this callback in a send message function + +```cs +[Command("ping")] +public async Task ping() +{ + var options = new RequestOptions() + { + RatelimitCallback = MyRatelimitCallback + }; + + await Context.Channel.SendMessageAsync("Pong!", options: options); +} +``` + +Running this produces the following output: + +``` +False 5 4 2021-09-09 3:48:14 AM +00:00 00:00:05 a06de0de4a08126315431cc0c55ee3dc 00:00:00.9891364 channels/848511736872828929/messages +``` diff --git a/docs/guides/emoji/emoji.md b/docs/guides/emoji/emoji.md index 60a84409c..dbf654bbf 100644 --- a/docs/guides/emoji/emoji.md +++ b/docs/guides/emoji/emoji.md @@ -46,14 +46,16 @@ form; this can be obtained in several different ways. ### Emoji Declaration After obtaining the Unicode representation of the emoji, you may -create the @Discord.Emoji object by passing the string into its +create the @Discord.Emoji object by passing the string with unicode into its constructor (e.g. `new Emoji("👌");` or `new Emoji("\uD83D\uDC4C");`). Your method of declaring an @Discord.Emoji should look similar to this: - [!code-csharp[Emoji Sample](samples/emoji-sample.cs)] +Also you can use `Emoji.Parse()` or `Emoji.TryParse()` methods +for parsing emojis from strings like `:heart:`, `<3` or `❤`. + [FileFormat.Info]: https://www.fileformat.info/info/emoji/list.htm ## Emote @@ -97,4 +99,4 @@ this: ## Additional Information To learn more about emote and emojis and how they could be used, -see the documentation of @Discord.IEmote. \ No newline at end of file +see the documentation of @Discord.IEmote. diff --git a/docs/guides/guild_events/creating-guild-events.md b/docs/guides/guild_events/creating-guild-events.md new file mode 100644 index 000000000..64ac0de9b --- /dev/null +++ b/docs/guides/guild_events/creating-guild-events.md @@ -0,0 +1,31 @@ +--- +uid: Guides.GuildEvents.Creating +title: Creating Guild Events +--- + +# Creating guild events + +You can create new guild events by using the `CreateEventAsync` function on a guild. + +### Parameters + +| Name | Type | Summary | +| ------------- | --------------------------------- | ---------------------------------------------------------------------------- | +| name | `string` | Sets the name of the event. | +| startTime | `DateTimeOffset` | Sets the start time of the event. | +| type | `GuildScheduledEventType` | Sets the type of the event. | +| privacyLevel? | `GuildScheduledEventPrivacyLevel` | Sets the privacy level of the event | +| description? | `string` | Sets the description of the event. | +| endTime? | `DateTimeOffset?` | Sets the end time of the event. | +| channelId? | `ulong?` | Sets the channel id of the event, only valid on stage or voice channel types | +| location? | `string` | Sets the location of the event, only valid on external types | + +Lets create a basic test event. + +```cs +var guild = client.GetGuild(guildId); + +var guildEvent = await guild.CreateEventAsync("test event", DateTimeOffset.UtcNow.AddDays(1), GuildScheduledEventType.External, endTime: DateTimeOffset.UtcNow.AddDays(2), location: "Space"); +``` + +This code will create an event that lasts a day and starts tomorrow. It will be an external event thats in space. diff --git a/docs/guides/guild_events/getting-event-users.md b/docs/guides/guild_events/getting-event-users.md new file mode 100644 index 000000000..f4b5388a0 --- /dev/null +++ b/docs/guides/guild_events/getting-event-users.md @@ -0,0 +1,16 @@ +--- +uid: Guides.GuildEvents.GettingUsers +title: Getting Guild Event Users +--- + +# Getting Event Users + +You can get a collection of users who are currently interested in the event by calling `GetUsersAsync`. This method works like any other get users method as in it returns an async enumerable. This method also supports pagination by user id. + +```cs +// get all users and flatten the result into one collection. +var users = await event.GetUsersAsync().FlattenAsync(); + +// get users around the 613425648685547541 id. +var aroundUsers = await event.GetUsersAsync(613425648685547541, Direction.Around).FlattenAsync(); +``` diff --git a/docs/guides/guild_events/intro.md b/docs/guides/guild_events/intro.md new file mode 100644 index 000000000..b60a8c70d --- /dev/null +++ b/docs/guides/guild_events/intro.md @@ -0,0 +1,41 @@ +--- +uid: Guides.GuildEvents.Intro +title: Introduction to Guild Events +--- + +# Guild Events + +Guild events are a way to host events within a guild. They offer alot of features and flexibility. + +## Getting started with guild events + +You can access any events within a guild by calling `GetEventsAsync` on a guild. + +```cs +var guildEvents = await guild.GetEventsAsync(); +``` + +If your working with socket guilds you can just use the `Events` property: + +```cs +var guildEvents = guild.Events; +``` + +There are also new gateway events that you can hook to receive guild scheduled events on. + +```cs +// Fired when a guild event is cancelled. +client.GuildScheduledEventCancelled += ... + +// Fired when a guild event is completed. +client.GuildScheduledEventCompleted += ... + +// Fired when a guild event is started. +client.GuildScheduledEventStarted += ... + +// Fired when a guild event is created. +client.GuildScheduledEventCreated += ... + +// Fired when a guild event is updated. +client.GuildScheduledEventUpdated += ... +``` diff --git a/docs/guides/guild_events/modifying-events.md b/docs/guides/guild_events/modifying-events.md new file mode 100644 index 000000000..05e14ec98 --- /dev/null +++ b/docs/guides/guild_events/modifying-events.md @@ -0,0 +1,23 @@ +--- +uid: Guides.GuildEvents.Modifying +title: Modifying Guild Events +--- + +# Modifying Events + +You can modify events using the `ModifyAsync` method to modify the event, heres the properties you can modify: + +| Name | Type | Description | +| ------------ | --------------------------------- | -------------------------------------------- | +| ChannelId | `ulong?` | Gets or sets the channel id of the event. | +| string | `string` | Gets or sets the location of this event. | +| Name | `string` | Gets or sets the name of the event. | +| PrivacyLevel | `GuildScheduledEventPrivacyLevel` | Gets or sets the privacy level of the event. | +| StartTime | `DateTimeOffset` | Gets or sets the start time of the event. | +| EndTime | `DateTimeOffset` | Gets or sets the end time of the event. | +| Description | `string` | Gets or sets the description of the event. | +| Type | `GuildScheduledEventType` | Gets or sets the type of the event. | +| Status | `GuildScheduledEventStatus` | Gets or sets the status of the event. | + +> [!NOTE] +> All of these properties are optional. diff --git a/docs/guides/interactions/application-commands/01-getting-started.md b/docs/guides/interactions/application-commands/01-getting-started.md new file mode 100644 index 000000000..fc8c8fe30 --- /dev/null +++ b/docs/guides/interactions/application-commands/01-getting-started.md @@ -0,0 +1,32 @@ +--- +uid: Guides.SlashCommands.Intro +title: Introduction to slash commands +--- + + +# Getting started with application commands. + +Welcome! This guide will show you how to use application commands. + +## What is an application command? + +Application commands consist of three different types. Slash commands, context menu User commands and context menu Message commands. +Slash commands are made up of a name, description, and a block of options, which you can think of like arguments to a function. The name and description help users find your command among many others, and the options validate user input as they fill out your command. +Message and User commands are only a name, to the user. So try to make the name descriptive. They're accessed by right clicking (or long press, on mobile) a user or a message, respectively. + +All three varieties of application commands have both Global and Guild variants. Your global commands are available in every guild that adds your application. You can also make commands for a specific guild; they're only available in that guild. The User and Message commands are more limited in quantity than the slash commands. For specifics, check out their respective guide pages. + +An Interaction is the message that your application receives when a user uses a command. It includes the values that the user submitted, as well as some metadata about this particular instance of the command being used: the guild_id, channel_id, member and other fields. You can find all the values in our data models. + +## Authorizing your bot for application commands + +There is a new special OAuth2 scope for applications called `applications.commands`. In order to make Application Commands work within a guild, the guild must authorize your application with the `applications.commands` scope. The bot scope is not enough. + +Head over to your discord applications OAuth2 screen and make sure to select the `application.commands` scope. + +![OAuth2 scoping](slash-commands/images/oauth.png) + +From there you can then use the link to add your bot to a server. + +> [!NOTE] +> In order for users in your guild to use your slash commands, they need to have the "Use Slash Command" permission on the guild. diff --git a/docs/guides/interactions/application-commands/context-menu-commands/creating-context-menu-commands.md b/docs/guides/interactions/application-commands/context-menu-commands/creating-context-menu-commands.md new file mode 100644 index 000000000..02a9cde14 --- /dev/null +++ b/docs/guides/interactions/application-commands/context-menu-commands/creating-context-menu-commands.md @@ -0,0 +1,105 @@ +--- +uid: Guides.ContextCommands.Creating +title: Creating Context Commands +--- + +# Creating context menu commands. + +There are two kinds of Context Menu Commands: User Commands and Message Commands. +Each of these have a Global and Guild variant. +Global menu commands are available for every guild that adds your app. An individual app's global commands are also available in DMs if that app has a bot that shares a mutual guild with the user. + +Guild commands are specific to the guild you specify when making them. Guild commands are not available in DMs. Command names are unique per application within each scope (global and guild). That means: + +- Your app cannot have two global commands with the same name +- Your app cannot have two guild commands within the same name on the same guild +- Your app can have a global and guild command with the same name +- Multiple apps can have commands with the same names + +**Note**: Apps can have a maximum of 5 global context menu commands, and an additional 5 guild-specific context menu commands per guild. + +If you don't have the code for a bot ready yet please follow [this guide](https://docs.stillu.cc/guides/getting_started/first-bot.html). + +## UserCommandBuilder + +The context menu user command builder will help you create user commands. The builder has these available fields and methods: + +| Name | Type | Description | +| -------- | -------- | ------------------------------------------------------------------------------------------------ | +| Name | string | The name of this context menu command. | +| WithName | Function | Sets the field name. | +| Build | Function | Builds the builder into the appropriate `UserCommandProperties` class used to make Menu commands | + +## MessageCommandBuilder + +The context menu message command builder will help you create message commands. The builder has these available fields and methods: + +| Name | Type | Description | +| -------- | -------- | --------------------------------------------------------------------------------------------------- | +| Name | string | The name of this context menu command. | +| WithName | Function | Sets the field name. | +| Build | Function | Builds the builder into the appropriate `MessageCommandProperties` class used to make Menu commands | + +**Note**: Context Menu command names can be upper and lowercase, and use spaces. + +Let's use the user command builder to make a global and guild command. + +```cs +// Let's hook the ready event for creating our commands in. +client.Ready += Client_Ready; + +... + +public async Task Client_Ready() +{ + // Let's build a guild command! We're going to need a guild so lets just put that in a variable. + var guild = client.GetGuild(guildId); + + // Next, lets create our user and message command builder. This is like the embed builder but for context menu commands. + var guildUserCommand = new UserCommandBuilder(); + var guildMessageCommand = new MessageCommandBuilder(); + + // Note: Names have to be all lowercase and match the regular expression ^[\w -]{3,32}$ + guildUserCommand.WithName("Guild User Command"); + guildMessageCommand.WithName("Guild Message Command"); + + // Descriptions are not used with User and Message commands + //guildCommand.WithDescription(""); + + // Let's do our global commands + var globalUserCommand = new UserCommandBuilder(); + globalCommand.WithName("Global User Command"); + var globalMessageCommand = new MessageCommandBuilder(); + globalMessageCommand.WithName("Global Message Command"); + + + try + { + // Now that we have our builder, we can call the BulkOverwriteApplicationCommandAsync to make our context commands. Note: this will overwrite all your previous commands with this array. + await guild.BulkOverwriteApplicationCommandAsync(new ApplicationCommandProperties[] + { + guildUserCommand.Build(), + guildMessageCommand.Build() + }); + + // With global commands we dont need the guild. + await client.BulkOverwriteGlobalApplicationCommandsAsync(new ApplicationCommandProperties[] + { + globalUserCommand.Build(), + globalMessageCommand.Build() + }) + } + catch(ApplicationCommandException exception) + { + // If our command was invalid, we should catch an ApplicationCommandException. This exception contains the path of the error as well as the error message. You can serialize the Error field in the exception to get a visual of where your error is. + var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented); + + // You can send this error somewhere or just print it to the console, for this example we're just going to print it. + Console.WriteLine(json); + } +} + +``` + +> [!NOTE] +> Application commands only need to be created once. They do _not_ have to be 'created' on every startup or connection. The example simple shows creating them in the ready event as it's simpler than creating normal bot commands to register application commands. diff --git a/docs/guides/interactions/application-commands/context-menu-commands/receiving-context-menu-command-events.md b/docs/guides/interactions/application-commands/context-menu-commands/receiving-context-menu-command-events.md new file mode 100644 index 000000000..d4e973d04 --- /dev/null +++ b/docs/guides/interactions/application-commands/context-menu-commands/receiving-context-menu-command-events.md @@ -0,0 +1,33 @@ +--- +uid: Guides.ContextCommands.Reveiving +title: Receiving Context Commands +--- + +# Receiving Context Menu events + +User commands and Message commands have their own unique event just like the other interaction types. For user commands the event is `UserCommandExecuted` and for message commands the event is `MessageCommandExecuted`. + +```cs +// For message commands +client.MessageCommandExecuted += MessageCommandHandler; + +// For user commands +client.UserCommandExecuted += UserCommandHandler; + +... + +public async Task MessageCommandHandler(SocketMessageCommand arg) +{ + Console.Writeline("Message command received!"); +} + +public async Task UserCommandHandler(SocketUserCommand arg) +{ + Console.Writeline("User command received!"); +} +``` + +User commands contain a SocketUser object called `Member` in their data class, showing the user that was clicked to run the command. +Message commands contain a SocketMessage object called `Message` in their data class, showing the message that was clicked to run the command. + +Both return the user who ran the command, the guild (if any), channel, etc. \ No newline at end of file diff --git a/docs/guides/interactions/application-commands/slash-commands/02-creating-slash-commands.md b/docs/guides/interactions/application-commands/slash-commands/02-creating-slash-commands.md new file mode 100644 index 000000000..9e35de285 --- /dev/null +++ b/docs/guides/interactions/application-commands/slash-commands/02-creating-slash-commands.md @@ -0,0 +1,98 @@ +--- +uid: Guides.SlashCommands.Creating +title: Creating Slash Commands +--- + +# Creating your first slash commands. + +There are two kinds of Slash Commands: global commands and guild commands. +Global commands are available for every guild that adds your app. An individual app's global commands are also available in DMs if that app has a bot that shares a mutual guild with the user. + +Guild commands are specific to the guild you specify when making them. Guild commands are not available in DMs. Command names are unique per application within each scope (global and guild). That means: + +- Your app cannot have two global commands with the same name +- Your app cannot have two guild commands within the same name on the same guild +- Your app can have a global and guild command with the same name +- Multiple apps can have commands with the same names + +**Note**: Apps can have a maximum of 100 global commands, and an additional 100 guild-specific commands per guild. + +**Note**: Global commands will take up to 1 hour to create, delete or modify on guilds. If you need to update a command quickly for testing you can create it as a guild command. + +If you don't have the code for a bot ready yet please follow [this guide](https://docs.stillu.cc/guides/getting_started/first-bot.html). + +## SlashCommandBuilder + +The slash command builder will help you create slash commands. The builder has these available fields and methods: + +| Name | Type | Description | +| --------------------- | -------------------------------- | -------------------------------------------------------------------------------------------- | +| MaxNameLength | const int | The maximum length of a name for a slash command allowed by Discord. | +| MaxDescriptionLength | const int | The maximum length of a commands description allowed by Discord. | +| MaxOptionsCount | const int | The maximum count of command options allowed by Discord | +| Name | string | The name of this slash command. | +| Description | string | A 1-100 length description of this slash command | +| Options | List\ | The options for this command. | +| DefaultPermission | bool | Whether the command is enabled by default when the app is added to a guild. | +| WithName | Function | Sets the field name. | +| WithDescription | Function | Sets the description of the current command. | +| WithDefaultPermission | Function | Sets the default permission of the current command. | +| AddOption | Function | Adds an option to the current slash command. | +| Build | Function | Builds the builder into a `SlashCommandCreationProperties` class used to make slash commands | + +> [!NOTE] +> Slash command names must be all lowercase! + +## Creating a Slash Command + +Let's use the slash command builder to make a global and guild command. + +```cs +// Let's hook the ready event for creating our commands in. +client.Ready += Client_Ready; + +... + +public async Task Client_Ready() +{ + // Let's build a guild command! We're going to need a guild so lets just put that in a variable. + var guild = client.GetGuild(guildId); + + // Next, lets create our slash command builder. This is like the embed builder but for slash commands. + var guildCommand = new SlashCommandBuilder(); + + // Note: Names have to be all lowercase and match the regular expression ^[\w-]{3,32}$ + guildCommand.WithName("first-command"); + + // Descriptions can have a max length of 100. + guildCommand.WithDescription("This is my first guild slash command!"); + + // Let's do our global command + var globalCommand = new SlashCommandBuilder(); + globalCommand.WithName("first-global-command"); + globalCommand.WithDescription("This is my frist global slash command"); + + try + { + // Now that we have our builder, we can call the CreateApplicationCommandAsync method to make our slash command. + await guild.CreateApplicationCommandAsync(guildCommand.Build()); + + // With global commands we dont need the guild. + await client.CreateGlobalApplicationCommandAsync(globalCommand.Build()); + // Using the ready event is a simple implementation for the sake of the example. Suitable for testing and development. + // For a production bot, it is recommended to only run the CreateGlobalApplicationCommandAsync() once for each command. + } + catch(ApplicationCommandException exception) + { + // If our command was invalid, we should catch an ApplicationCommandException. This exception contains the path of the error as well as the error message. You can serialize the Error field in the exception to get a visual of where your error is. + var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented); + + // You can send this error somewhere or just print it to the console, for this example we're just going to print it. + Console.WriteLine(json); + } +} + +``` + +> [!NOTE] +> Slash commands only need to be created once. They do _not_ have to be 'created' on every startup or connection. The example simple shows creating them in the ready event as it's simpler than creating normal bot commands to register slash commands. The global commands take up to an hour to register every time the CreateGlobalApplicationCommandAsync() is called for a given command. diff --git a/docs/guides/interactions/application-commands/slash-commands/03-responding-to-slash-commands.md b/docs/guides/interactions/application-commands/slash-commands/03-responding-to-slash-commands.md new file mode 100644 index 000000000..3dbc579fe --- /dev/null +++ b/docs/guides/interactions/application-commands/slash-commands/03-responding-to-slash-commands.md @@ -0,0 +1,40 @@ +--- +uid: Guides.SlashCommands.Receiving +title: Receiving and Responding to Slash Commands +--- + +# Responding to interactions. + +Interactions are the base thing sent over by Discord. Slash commands are one of the interaction types. We can listen to the `SlashCommandExecuted` event to respond to them. Lets add this to our code: + +```cs +client.SlashCommandExecuted += SlashCommandHandler; + +... + +private async Task SlashCommandHandler(SocketSlashCommand command) +{ + +} +``` + +With every type of interaction there is a `Data` field. This is where the relevant information lives about our command that was executed. In our case, `Data` is a `SocketSlashCommandData` instance. In the data class, we can access the name of the command triggered as well as the options if there were any. For this example, we're just going to respond with the name of the command executed. + +```cs +private async Task SlashCommandHandler(SocketSlashCommand command) +{ + await command.RespondAsync($"You executed {command.Data.Name}"); +} +``` + +Let's try this out! + +![slash command picker](images/slashcommand1.png) + +![slash command result](images/slashcommand2.png) + +> [!NOTE] +> After receiving an interaction, you must respond to acknowledge it. You can choose to respond with a message immediately using `RespondAsync()` or you can choose to send a deferred response with `DeferAsync()`. +> If choosing a deferred response, the user will see a loading state for the interaction, and you'll have up to 15 minutes to edit the original deferred response using `ModifyOriginalResponseAsync()`. You can read more about response types [here](https://discord.com/developers/docs/interactions/slash-commands#interaction-response) + +This seems to be working! Next, we will look at parameters for slash commands. diff --git a/docs/guides/interactions/application-commands/slash-commands/04-parameters.md b/docs/guides/interactions/application-commands/slash-commands/04-parameters.md new file mode 100644 index 000000000..6afd83729 --- /dev/null +++ b/docs/guides/interactions/application-commands/slash-commands/04-parameters.md @@ -0,0 +1,102 @@ +--- +uid: Guides.SlashCommands.Parameters +title: Slash Command Parameters +--- + +# Slash command parameters + +Slash commands can have a bunch of parameters, each their own type. Let's first go over the types of parameters we can have. + +| Name | Description | +| --------------- | -------------------------------------------------- | +| SubCommand | A subcommand inside of a subcommand group. | +| SubCommandGroup | The parent command group of subcommands. | +| String | A string of text. | +| Integer | A number. | +| Boolean | True or False. | +| User | A user | +| Channel | A channel, this includes voice text and categories | +| Role | A role. | +| Mentionable | A role or a user. | + +Each one of the parameter types has its own DNET type in the `SocketSlashCommandDataOption`'s Value field: +| Name | C# Type | +| --------------- | ------------------------------------------------ | +| SubCommand | NA | +| SubCommandGroup | NA | +| String | `string` | +| Integer | `int` | +| Boolean | `bool` | +| User | `SocketGuildUser` or `SocketUser` | +| Role | `SocketRole` | +| Channel | `SocketChannel` | +| Mentionable | `SocketUser`, `SocketGuildUser`, or `SocketRole` | + +Let's start by making a command that takes in a user and lists their roles. + +```cs +client.Ready += Client_Ready; + +... + +public async Task Client_Ready() +{ + ulong guildId = 848176216011046962; + + var guildCommand = new SlashCommandBuilder() + .WithName("list-roles") + .WithDescription("Lists all roles of a user.") + .AddOption("user", ApplicationCommandOptionType.User, "The users whos roles you want to be listed", isRequired: true); + + try + { + await client.Rest.CreateGuildCommand(guildCommand.Build(), guildId); + } + catch(ApplicationCommandException exception) + { + var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented); + Console.WriteLine(json); + } +} + +``` + +![list roles command](images/listroles1.png) + +That seems to be working, now Let's handle the interaction. + +```cs +private async Task SlashCommandHandler(SocketSlashCommand command) +{ + // Let's add a switch statement for the command name so we can handle multiple commands in one event. + switch(command.Data.Name) + { + case "list-roles": + await HandleListRoleCommand(command); + break; + } +} + +private async Task HandleListRoleCommand(SocketSlashCommand command) +{ + // We need to extract the user parameter from the command. since we only have one option and it's required, we can just use the first option. + var guildUser = (SocketGuildUser)command.Data.Options.First().Value; + + // We remove the everyone role and select the mention of each role. + var roleList = string.Join(",\n", guildUser.Roles.Where(x => !x.IsEveryone).Select(x => x.Mention)); + + var embedBuiler = new EmbedBuilder() + .WithAuthor(guildUser.ToString(), guildUser.GetAvatarUrl() ?? guildUser.GetDefaultAvatarUrl()) + .WithTitle("Roles") + .WithDescription(roleList) + .WithColor(Color.Green) + .WithCurrentTimestamp(); + + // Now, Let's respond with the embed. + await command.RespondAsync(embed: embedBuiler.Build()); +} +``` + +![working list roles](images/listroles2.png) + +That has worked! Next, we will go over responding ephemerally. diff --git a/docs/guides/interactions/application-commands/slash-commands/05-responding-ephemerally.md b/docs/guides/interactions/application-commands/slash-commands/05-responding-ephemerally.md new file mode 100644 index 000000000..10b04a8d2 --- /dev/null +++ b/docs/guides/interactions/application-commands/slash-commands/05-responding-ephemerally.md @@ -0,0 +1,23 @@ +--- +uid: Guides.SlashCommands.Ephemeral +title: Ephemeral Responses +--- + +# Responding ephemerally + +What is an ephemeral response? Basically, only the user who executed the command can see the result of it, this is pretty simple to implement. + +> [!NOTE] +> You don't have to run arg.DeferAsync() to capture the interaction, you can use arg.RespondAsync() with a message to capture it, this also follows the ephemeral rule. + +When responding with either `FollowupAsync` or `RespondAsync` you can pass in an `ephemeral` property. When setting it to true it will respond ephemerally, false and it will respond non-ephemerally. + +Let's use this in our list role command. + +```cs +await command.RespondAsync(embed: embedBuiler.Build(), ephemeral: true); +``` + +Running the command now only shows the message to us! + +![ephemeral command](images/ephemeral1.png) \ No newline at end of file diff --git a/docs/guides/interactions/application-commands/slash-commands/06-subcommands.md b/docs/guides/interactions/application-commands/slash-commands/06-subcommands.md new file mode 100644 index 000000000..83d7b283c --- /dev/null +++ b/docs/guides/interactions/application-commands/slash-commands/06-subcommands.md @@ -0,0 +1,219 @@ +--- +uid: Guides.SlashCommands.SubCommand +title: Sub Commands +--- + +# Subcommands + +Subcommands allow you to have multiple commands available in a single command. They can be useful for representing sub options for a command. For example: A settings command. Let's first look at some limitations with subcommands set by discord. + +- An app can have up to 25 subcommand groups on a top-level command +- An app can have up to 25 subcommands within a subcommand group +- commands can have up to 25 `options` +- options can have up to 25 `choices` + +``` +VALID + +command +| +|__ subcommand +| +|__ subcommand + +---- + +command +| +|__ subcommand-group + | + |__ subcommand +| +|__ subcommand-group + | + |__ subcommand + + +------- + +INVALID + + +command +| +|__ subcommand-group + | + |__ subcommand-group +| +|__ subcommand-group + | + |__ subcommand-group + +---- + +INVALID + +command +| +|__ subcommand + | + |__ subcommand-group +| +|__ subcommand + | + |__ subcommand-group +``` + +Let's write a settings command that can change 3 fields in our bot. + +```cs +public string FieldA { get; set; } = "test"; +public int FieldB { get; set; } = 10; +public bool FieldC { get; set; } = true; + +public async Task Client_Ready() +{ + ulong guildId = 848176216011046962; + + var guildCommand = new SlashCommandBuilder() + .WithName("settings") + .WithDescription("Changes some settings within the bot.") + .AddOption(new SlashCommandOptionBuilder() + .WithName("field-a") + .WithDescription("Gets or sets the field A") + .WithType(ApplicationCommandOptionType.SubCommandGroup) + .AddOption(new SlashCommandOptionBuilder() + .WithName("set") + .WithDescription("Sets the field A") + .WithType(ApplicationCommandOptionType.SubCommand) + .AddOption("value", ApplicationCommandOptionType.String, "the value to set the field", isRequired: true) + ).AddOption(new SlashCommandOptionBuilder() + .WithName("get") + .WithDescription("Gets the value of field A.") + .WithType(ApplicationCommandOptionType.SubCommand) + ) + ).AddOption(new SlashCommandOptionBuilder() + .WithName("field-b") + .WithDescription("Gets or sets the field B") + .WithType(ApplicationCommandOptionType.SubCommandGroup) + .AddOption(new SlashCommandOptionBuilder() + .WithName("set") + .WithDescription("Sets the field B") + .WithType(ApplicationCommandOptionType.SubCommand) + .AddOption("value", ApplicationCommandOptionType.Integer, "the value to set the fie to.", isRequired: true) + ).AddOption(new SlashCommandOptionBuilder() + .WithName("get") + .WithDescription("Gets the value of field B.") + .WithType(ApplicationCommandOptionType.SubCommand) + ) + ).AddOption(new SlashCommandOptionBuilder() + .WithName("field-c") + .WithDescription("Gets or sets the field C") + .WithType(ApplicationCommandOptionType.SubCommandGroup) + .AddOption(new SlashCommandOptionBuilder() + .WithName("set") + .WithDescription("Sets the field C") + .WithType(ApplicationCommandOptionType.SubCommand) + .AddOption("value", ApplicationCommandOptionType.Boolean, "the value to set the fie to.", isRequired: true) + ).AddOption(new SlashCommandOptionBuilder() + .WithName("get") + .WithDescription("Gets the value of field C.") + .WithType(ApplicationCommandOptionType.SubCommand) + ) + ); + + try + { + await client.Rest.CreateGuildCommand(guildCommand.Build(), guildId); + } + catch(ApplicationCommandException exception) + { + var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented); + Console.WriteLine(json); + } +} +``` + +All that code generates a command that looks like this: +![settings](images/settings1.png) + +Now that we have our command made, we need to handle the multiple options with this command. So lets add this into our handler: + +```cs +private async Task SlashCommandHandler(SocketSlashCommand command) +{ + // Let's add a switch statement for the command name so we can handle multiple commands in one event. + switch(command.Data.Name) + { + case "list-roles": + await HandleListRoleCommand(command); + break; + case "settings": + await HandleSettingsCommand(command); + break; + } +} + +private async Task HandleSettingsCommand(SocketSlashCommand command) +{ + // First lets extract our variables + var fieldName = command.Data.Options.First().Name; + var getOrSet = command.Data.Options.First().Options.First().Name; + // Since there is no value on a get command, we use the ? operator because "Options" can be null. + var value = command.Data.Options.First().Options.First().Options?.FirstOrDefault().Value; + + switch (fieldName) + { + case "field-a": + { + if(getOrSet == "get") + { + await command.RespondAsync($"The value of `field-a` is `{FieldA}`"); + } + else if (getOrSet == "set") + { + this.FieldA = (string)value; + await command.RespondAsync($"`field-a` has been set to `{FieldA}`"); + } + } + break; + case "field-b": + { + if (getOrSet == "get") + { + await command.RespondAsync($"The value of `field-b` is `{FieldB}`"); + } + else if (getOrSet == "set") + { + this.FieldB = (int)value; + await command.RespondAsync($"`field-b` has been set to `{FieldB}`"); + } + } + break; + case "field-c": + { + if (getOrSet == "get") + { + await command.RespondAsync($"The value of `field-c` is `{FieldC}`"); + } + else if (getOrSet == "set") + { + this.FieldC = (bool)value; + await command.RespondAsync($"`field-c` has been set to `{FieldC}`"); + } + } + break; + } +} + +``` + +Now, let's try this out! Running the 3 get commands seems to get the default values we set. + +![settings get](images/settings2.png) + +Now let's try changing each to a different value. + +![settings set](images/settings3.png) + +That has worked! Next, let't look at choices in commands. diff --git a/docs/guides/interactions/application-commands/slash-commands/07-choice-slash-command.md b/docs/guides/interactions/application-commands/slash-commands/07-choice-slash-command.md new file mode 100644 index 000000000..3951e1141 --- /dev/null +++ b/docs/guides/interactions/application-commands/slash-commands/07-choice-slash-command.md @@ -0,0 +1,85 @@ +--- +uid: Guides.SlashCommands.Choices +title: Slash Command Choices +--- + +# Slash Command Choices. + +With slash command options you can add choices, making the user select between some set values. Lets create a command that asks how much they like our bot! + +Let's set up our slash command: + +```cs +private async Task Client_Ready() +{ + ulong guildId = 848176216011046962; + + var guildCommand = new SlashCommandBuilder() + .WithName("feedback") + .WithDescription("Tell us how much you are enjoying this bot!") + .AddOption(new SlashCommandOptionBuilder() + .WithName("rating") + .WithDescription("The rating your willing to give our bot") + .WithRequired(true) + .AddChoice("Terrible", 1) + .AddChoice("Meh", 2) + .AddChoice("Good", 3) + .AddChoice("Lovely", 4) + .AddChoice("Excellent!", 5) + .WithType(ApplicationCommandOptionType.Integer) + ).Build(); + + try + { + await client.Rest.CreateGuildCommand(guildCommand.Build(), guildId); + } + catch(ApplicationCommandException exception) + { + var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented); + Console.WriteLine(json); + } +} +``` +> [!NOTE] +> Your `ApplicationCommandOptionType` specifies which type your choices are, you need to use `ApplicationCommandOptionType.Integer` for choices whos values are whole numbers, `ApplicationCommandOptionType.Number` for choices whos values are doubles, and `ApplicationCommandOptionType.String` for string values. + +We have defined 5 choices for the user to pick from, each choice has a value assigned to it. The value can either be a string or an int. In our case we're going to use an int. This is what the command looks like: + +![feedback style](images/feedback1.png) + +Lets add our code for handling the interaction. + +```cs +private async Task SlashCommandHandler(SocketSlashCommand command) +{ + // Let's add a switch statement for the command name so we can handle multiple commands in one event. + switch(command.Data.Name) + { + case "list-roles": + await HandleListRoleCommand(command); + break; + case "settings": + await HandleSettingsCommand(command); + break; + case "feedback": + await HandleFeedbackCommand(command); + break; + } +} + +private async Task HandleFeedbackCommand(SocketSlashCommand command) +{ + var embedBuilder = new EmbedBuilder() + .WithAuthor(command.User) + .WithTitle("Feedback") + .WithDescription($"Thanks for your feedback! You rated us {command.Data.Options.First().Value}/5") + .WithColor(Color.Green) + .WithCurrentTimestamp(); + + await command.RespondAsync(embed: embedBuilder.Build()); +} +``` + +And this is the result: + +![feedback working](images/feedback2.png) diff --git a/docs/guides/interactions/application-commands/slash-commands/08-bulk-overwrite-of-global-slash-commands.md b/docs/guides/interactions/application-commands/slash-commands/08-bulk-overwrite-of-global-slash-commands.md new file mode 100644 index 000000000..095eda14f --- /dev/null +++ b/docs/guides/interactions/application-commands/slash-commands/08-bulk-overwrite-of-global-slash-commands.md @@ -0,0 +1,40 @@ +--- +uid: Guides.SlashCommands.BulkOverwrite +title: Slash Command Bulk Overwrites +--- + +If you have too many global commands then you might want to consider using the bulk overwrite function. + +```cs +public async Task Client_Ready() +{ + List applicationCommandProperties = new(); + try + { + // Simple help slash command. + SlashCommandBuilder globalCommandHelp = new SlashCommandBuilder(); + globalCommandHelp.WithName("help"); + globalCommandHelp.WithDescription("Shows information about the bot."); + applicationCommandProperties.Add(globalCommandHelp.Build()); + + // Slash command with name as its parameter. + SlashCommandOptionBuilder slashCommandOptionBuilder = new(); + slashCommandOptionBuilder.WithName("name"); + slashCommandOptionBuilder.WithType(ApplicationCommandOptionType.String); + slashCommandOptionBuilder.WithDescription("Add a family"); + slashCommandOptionBuilder.WithRequired(true); // Only add this if you want it to be required + + SlashCommandBuilder globalCommandAddFamily = new SlashCommandBuilder(); + globalCommandAddFamily.WithName("add-family"); + globalCommandAddFamily.WithDescription("Add a family"); + applicationCommandProperties.Add(globalCommandAddFamily.Build()); + + await _client.BulkOverwriteGlobalApplicationCommandsAsync(applicationCommandProperties.ToArray()); + } + catch (ApplicationCommandException exception) + { + var json = JsonConvert.SerializeObject(exception.Error, Formatting.Indented); + Console.WriteLine(json); + } +} +``` diff --git a/docs/guides/interactions/application-commands/slash-commands/images/ephemeral1.png b/docs/guides/interactions/application-commands/slash-commands/images/ephemeral1.png new file mode 100644 index 0000000000000000000000000000000000000000..61eab94b60e9b4366c64d0f7f983134f8947f2f4 GIT binary patch literal 37660 zcma&Nb8sfj7dE^b+qq-gwr$(Cu`xEbZ5w;XwrxAvIN8|x^8EgMzj~|QnwqKVp6=6g zru&@ktNS_;it-ZhFxW6Ze*A!!k`z_`@#E+I_iYaa@tvcWh4cOV@zX_FLik7RH16ql z0?a~4PUy#vx;WT(Bk=Duw41*LC& zB41O#x-72h_;NRYDo%1uG}F0V+yCf$b+a)4zBJw@dF)cK8jj8hai_s<1{mQ67$==X z+5E9WjW9zaKxqfRGvH7qG{gVPAddwiv3zI9;u;Z|V}=@~bM^~Q{#V5*I3)eMywN@s zEYp8729W{A{}Vv+|0%v&lH1e%rg8zy$8xh5_2%BzABiRX3u0pra{A{q88QyGjNl3}~*&!zssF!4< z8UL+`I6m#5)1VRTfK-;4+U)8ol->%H$uL}TSs4i%8#;@{^k6!ZiK%9lSV|!6^nZ$p zBYam7hN>KZpz7{3L{d{zv$V4tdc53FQdbWR4TX62;YR}i`VXD^jO#{$ZuOBlq@yFS zA)j}_bilLW@YkdSa19?w4qx*|PgYLXrN~mJyWJ@)nUMT^^CK=!$5#y`*AhwpDQgJ{ z^MrT4IV8_Y-D}TehBma!DXVs7IG4hHVO&U2)CMF~qH6Uj^qia=&Vy(cM!$CtRyH=H zt@d9YcT*fU5OzFn7rnvIsPXafhPiUbIlPWrQfG+9Y?z3#W&vpLWRq?%JfLi4Et z$Z{sf#I{AwWpBl6xU&_^Xa!cAKB`k4ik}D&M6nM^@_4S#Cc;WoJIMyGW|&8VVPDDz zzqi)6I;-QG4qdsOPG*TzC~kb#?7cNRF;cDkI_}L6sVlvMjF|Sd~I$G{4Zq5?71a zARE-Yr_mW>#<%yWjD?pMsEkXx&Vy=1n-N~!6JO6|Q*4YsT}SoS!K>%!jtm}#`LC6u z6X4&!M>}M0%y+e={_r7|wcgsF%p!3El?nNokfJ&|Sr?$wGcyvtCM+QQ1QFHXYeldL zLiSL>@uu#It?HJUFSZ7-&NhLktjZlF z&2*tnG@REx#ILv#IUnuSM^T7uG!p#UUp?#l+n~PtUc$oYa-=GYmlUgLLUz`4-2^eySUG&f*4LS`zq3Ax{nxc@}x&^pC#!1Isz>SkQ87xa6(&FZ(uGL;-fL56FQ^C6-mNpI! zQ+qk)b}IRER+i&+Z$NFIws16w=*UvmJrLZ$R<0jQA4Lk~9Bn<=5~c+g#ZU;l;?%VV z6`|{m2}wyFjoFGd0chTmCNWv zGx*hK$@K+Rb%$i}^WZOgAxqHtj2$qM58U&^ajX3v{6R;CE4bdRV7lYzA1GqL>My<{BD8N;OBw>IYWnhOg^db^Rly?{1;Q?kTcMJ(HPK}GB(!z&< zQM1fm?e~a@P#RNTwA?H(MhFd#R;GKOuwk8sG#vkhrvxEnOw$I{}y{1{%Wgpe*>7Bnf0GPj9(+$ zXcEdJ2EQ(s1haLtviy`snX^dR08SzI>U$&oGJTOJVgiiRm~NRTXkx^dbOy!p$SGl{ z-;<)OYuki3Gonx;IO*EMjvs{kV{7&PY3tIwyfupBBV9??y-y%j!Yk|D2r$bG*F$@h`4o5qx^T7bqfIbG<63^BS%I*+#@2+tr=DqE~ znN_9q+$V6_$;@)J>S`KGUe%!pscFrYbp29NK}u-pQ`vUC z8UC;)=J`5iC1F=q(ASrwkr4^u!J$AbNl-fvr!ijeb*|J6_DiuoX`j9&gwUCk{SS6% z41QTr-qE*jnzEPWKbMuAaY?sVlEsWus)fMaJQlT=Z*JpKTG_WCL)Y4_Oi#obX zont93sZ!=OvLMbmF6eBYc*Y)KNc77L`DackX!SCwi5ZGTFKKgD2;H{907dX5ZyCVZ#lsdi=4;_SV5ZM}Z>* z9kyFZGQoA$eGcfjNK^NI*ocG)M*3bku;{fT+xIK5%5bDiUaf<;(jF8%>pg@OlhHy{ zEKPI5me6#^j)!1O_?d(ng{CEGhbJW^5dyNqXP1w}^z29~tIia{=>VC_3&zo`3Kr(( z(n8bI)5B^SdQ^X;H3x>oh8$Nr=mst6{^4mj;7Zu#42LORYV+Rgeze{lBko1G(-`Ks zBG|tkWyGWU`3O}OtL`@C?ZkO|JM?%bU7Qw4+{ZOX=ZYJ<{tkB9B|rE?S~i=0)lht2 zCx~x4g{O+98)BJbw5q@=Wau}ZUVn#h=J%|#k+G!Y@O_hL;2sOSqPixkw?&kYK7~N* zdMU%-IB~~k68BpON>Oe{7ISzZWN|{4KAYFTTXTJ z*x*4%$Xiu69L2py6VhxmUc5i%f8uJhlu%MaPNmfftWYUSq_o(3hn-HF&`so{9S~pO zsfGF}7DSMVONNIvLq@vB1!W{pY_l%6anrkQAQSord_$uveCNxXXMMqiQNQ)FQY?uL za%hgOh1}SW&GCoYFCtQ}TT_-_98``7jnC+6!I{I;3907m+f9n11ieax5XR8KDKxJd zE-UXckxsKI+{LgqoS9X~rI8sYMX`hsjxSQIbUz77)=b;oOwKJ!e86|_&_;oC!Fcqi z>NSYhEb0KCZ9k66Oe=gV|l zAV~(8cj-((Lzg{Euuwx~AD%knl7&Q~c^@2%i;@j73WA9h0lb`@A8Blkd8}hIvCB00 z^RUH8(L`*+^zaMDl(_v$uQg24aX`{wi5zZoZQpAUKvv)BC%Jow6QMi)kjo1%Rd=54 zX54h3*z3iBkq_`}% zV&dkWucoQq+g{#}h#sw+GXA?_Pf?f6t3`jIq^(UY@Jg6j5%Nn{LnBU*kT4DhCpu1e z7Dq4l7*XrhE)x*?2a_mAkO!7WH~rkDU;N1}X&`Ptzs6><5tHhYJR$ec-4G!H2-PsZ zB}7~*`4u282m2M&{4YSVPTWvJMWw`ev$IXpZ5V`>#|+xsjBW3r$05u_pBsCy{B%%v zQmYxxBF~pvUXK?;#?oJ^n?T3F7ui7#mI!KpHWhSsm~Jp6j|*=CK;K(oK|h?GjZp3H zOZLbXReWPtXs&RV4zI_lC@bpjCB zY;+JZA(EOKcjSe??p+(vrbv5?IkjyP>OSzW^fkw^wd!+nm7M>&%;wOFH3#mof@oD6&!$RB6jM~&GnLES-@x=;vBYUUvJr@mW{9Tzc5nS!7lp2G7>8F8vhwy% ze`h~mO%zQ3rlnoL@ZuxZwx3a}s;Z90@j>mO+sI*HU?eSF3G+qVkQuas`TIT3n1V-v z^Nm&#%d8Sy=s$T72DidYVW>n7g5VqD->8h)IS;yk)k%gC8b-cf8;Kc*LPB>#EH*uH zWUdA@W~*}gPL*5#8$od?CFEF&Q1te{!F0-RgOCGdO>P9pi+v=k?5^Depw$-$Mt1|w zd10&6!W|rfpTkbNwcm4?KH`EU8|sHv=)pZ0Mdvl7vc>SdT{!)})x!tub0+T2I=xmz z-F&`Xk#KQgy**up4eZ4mXD22Sm(i`+xg|$4BoG8qQc?9SUv})l4mJlPN(c!Ezgvk` zQ|Pr_6LXbNxKH&!W}6Rw!{KZo(g+r~5NTVDX{2R+oMyOV@z|C%k+-^9Nmj_a_D0Zb z%=S!CU`Q)Pf1#>ypGmXqH#Ck7Npb@&OA3X-*XV=e`GM!~*9nTZG~o~?oZN%&!ctpW zVH}jk=?8;9EHi$lFGouQjHLXhM!w4a4+<1r%668p0A5--e5UA%3;9eJC(!(P6%Z?YO9pq>*q~~p8k@RtqTOlbbs)2!5%Tmd5q2bF;aN6%b*#Z(dr@$?WF9*bUU0K8{L^vIx(wg(1x7yrcqc^ zx9Ix4dy@MX{R=EM82U)*{o4JXu-Pf%6iH|VB84bH-9ScYqLzm7>--nCGcq8YQ*4tM zJ^^rNMG_zj#OhsTnKU8a4nI0U4L~I$m@La`g>`x?7fbJYcQZww=Fkg8ObC^fDaO)> z?1sIJ>Iq>F8r&1@^@F%acNfY+Id;ZkFP(kRi@M(TjGqz^nT9(lQ+(0$Lv)QhU4*QJ zn=EDA?`F_9YWMZxTIS!YhE}J|FcC`i^l8MM>9z_zjcbLuSv^fN-kh8$(8evDxF(rL zv5IUw2%Uo1G9vj|d?{*p&ugiLe{!G@AK5pT=oN$3ew~4lfiMy!r-w771tW|Jn9XWvSKO5>m_*JpU67`~`J|HFkZ z`q{LdqDIbN5F?^06;;RmzGjPj_63JCI7>3FP#uh++2f=o+2OSM7b?o13mFk|5}04D z+fjM^08zV4_%wYp4)H&nm&K?$dBE1X zfMCU8pRL3UJ0-z91kU}ML1N*?&`DJOp(1#JC*Go+?r@OEK=YID^KLwXM&wOq`z;*J zJhrgM?lFHguVJv(gDNEcdVU|fSXbdzLW%c!uQo~HnJf<`3h{FA+Yovm>)?jq@xA=;q#Nr+-_5YuR48 z2T%i0#^Zu&%cdqB?myC52_&cUBXRg}=AMXOGo*^^b9~9-h0XLeOdw9k>F!{U^c98~ znoYbSV?~muvP(P1XH=}YTQ5f0+O0u$}?=NuC9_4xL(2is$ zCCoDehsV_wQTT4qO#TJ)dL#~%|FJ&5tK>%Jss+@Yq~X!aXle`+lp%<%_aWhCS6q zwjj!(IM5BgjCY>0RASTTqsg1c5;=XShL~t9 z?l>ic(8%#d?Qf8@Lz}Fxs6Z=& z;&1}*FB5yBN@ART^EdaLyPK2rKMGOF&vD0SOf+VZ^>+m!=z>q#w)KKmlT{wIf=H1e zMjz-i0t*cF;26N3hR(a9&qU*n-j0I^pR?`Ce zXgK-+HvZT{i+q9$7VyVODL@t_ymEjJ8EXZsA9oXGoiypT|B;BC2yFP{xIbuo!r5@!ZhUKt@h%8LqJRM0{KXAfv#&)Y2s#H5_Zivv$1hP2GZcKBNY)S=?U}fZr zV#2?65w+d18NaP70M8C$G~aHttG5o5L8Xd(tkfvxz0xm^P}OYR8!Ke|w3}0s z#gZ<;5P%LbBAgA- z16&CqFCF@zAd>t@fsGgyMQJ^IDu=uJ{d%OA{CTJ7OKR>iCe6Exd&LpQ4*8b~Lntdlh(Sd9&EP4%=@Yiy|L6lgMfd|Ur{$G|QmysKz%ckUaC5olNBIScq z6tOuk^`RX5Q>2R+{_7F2q!NWLzT9YR^N z-ZBX;EmxCwbgD7GqLMw7Z97d+4^+E6G%wq7@pbT_S0g5p9J2mS)Q$tj8^U?vqr9>d zhQw@n@*lLq4i6(-cw2`_sqZ!~wy~s|auRDbCmH%qS34%l>CjOz7-_EnP=I~wOP11ED{dalZ`K*bI zFx;o$XC($7QEhVBV*XHoI|hFgE&0Z(3qNFO?_w_*s~SHUb+G$6 zmbll$a*8CjrKKxzC;WUH?otlBt9r_i{i2=nv~>PlYOMYC7XGaq^%J{#%TvS+X}_Sk z;Vn|jeU>#WRiV1X-*(}Af>ks%F>$UO59hA_+d32t#c^Cijyy1;Wa1y3%KEMb*oOmx zPjZrggj~8mIu)CXzB#V`DbmV3HV7{gFd?*W#>`?Lq|-b_nb#8)vgMMZHbQwi#6vl` zLtd5fxTx6bmveJ_it$q5s&j&wI;L0HM0iHyA;#EAq0SB4NDkRr2aFDVwv!o5;0;HU z!+~o>3Cj<-I=fUE5n{0BiC?UfT8!XDMcU})kC9HW$3}CVr|Ck+GZ{QMQRYWPLYoNQ zfYRx#0Hy?K#sc%$fxxz*lecAT!rVsVNgN8W=>Ey92u~C52rUQ6i!Dzr$vK@_!$;fV zn3B8F!*KSTf5#LsWl6S14v-P<2Ad%-lCUcUm9+{a?zYwHFWA>FF||ZdYO2HimgNos zY%Hj`qearIEX)au`cb#$ky*FCx?uKDob)faY^Oez!SD};UJ#1T_t8r=bj)nBP z2xfYeLo%@iwm`xEkva{q!c>@SQbNv)x)c}g8md9EU)&2Tjpo@GYI>^^-csIrISV`7 z$`?>~6{I=(PYHyH4RT$Nd9_=fUj#c_X6?;_YyIBeV$eUEn<@w@$e=Z-he_ZE-J2i~ zeD3GTpV3Ap8<&{a8xO1=awSq_x3o}h*ATN)nMzYTGc5H;=yf0!Lhr!qDEJr4CPt~j`+(PpOd!8H@_it2cM{CQ)*K5d+3OF%*9BYkBsfK3X^oRtnRfqRJxqALX5VH56=`>J-K%1bFsVe(o z3u2#LQfT6hv$%Z1UATPYP zH+#($;EhR=da#r14rqFVEBoYX{Pen2&TqFrkhxVvNV#b)-v=hmn2O_iW6OnHA*m`T+ABgiRhJC(fB) zRM;uf4Mzvau`a>48vOMt;_+ES-8f;6wnvlsry~z4K_kJ!JYG~ACTw?T10H%U%e{|S zoQNY)lI&Oz^bl4?Mf3>ks5fWDoQZUy{aL9 z0;TiKO4ajB=O%*x4B`QH)LjkyF*hgKm=BD^zPlke21?@iTdN$qiW6cn= zZc5L{hcVF;Nv~xXI5{tM;e7#^D%3 zK6rnxQrwstz+_e~f{Q8j07*&SxvW+5?R0+};l2K+17K z_&j-a8<>fqGUD(=o#g$B>~e}Lr?4dH<44~~oX-V5iW!PUq+%9-c9n918Uw8o(|y^y z6(x^}?a1aPHc_IwLzJ?hHKp~fUlB1E@2s!Rn?iX%<1{{^@2hUT500cJLBjsJSP>U< z-am=S+tnB1h;}SfD34Q)%hq=iNBC?<03&)0Y7fzJ2 z4ZS;?M7hKCtVSQ&%n3R23=VOSRsr0q57oKZfBVao`UC%*)>pp`;Z`@f@j<^9kUzKM|D4;A1GKHZt|+TP z8aR_PkI~UFpe{>p?jfl;T{`CeZs<2=surg0E=*3~Sgc}$ep4G5taHoe9tcvD9MQ2k zQ&d1axQAw+%#H_hAdJS?t`ds37OMpVj{=yBEVy2*?!+oId!AY?NB@+$Wl-%r^XmRL zxV}hyMFD2L81!fIH$V9XFQ-sBd$1J2h7EV*F`S8@hK%RV=iJG@Jef?j`$AKWC~rHK zb{Xqq0vk1Vb~PXOVraTNWs|T6@2m;kQ-*xXZ+`UHBCHA?2j<45E@vOvP@## zb^3MB*TmEiTL}v4aTBfUprP_f*DZDjw#p5?(XpAJFlvgz9ZeLd`G>~^5JwQ^?=Ijs zTh;j+i-&hgMLn&REr%EqSx-&C{_nbwP-nl( z&uU$rI5!8V%1TM1QvcJHRWFmjz8-Tj-KN!ixLs2$kSD5Y6Nw8l^oc3~_gXt4k0CZO zRBRL|khy6^J_#-`jSGJQauo`hZ^$htPKV?e2!36fm|;O?P=?{V{JlpIVj+Q5l^to^I zhaRQFikTek$Bm2(z7YP)`C*BsCl-ub%|l4i~ib2=|9NI7g=8kqfTCsY5?9DfR!Y!yPppc<@5x7; zcPF{pK>3Gf%y)*VOU#Q{oT^9M6EHPEmOKoD@>Kyod-}SB;SWnjO=WiZra0I!!m>T8 zU>(I&b76Uxr`Hth)mnZHsAMKTW5DFm^;E;OU z6rk2f>l(M?yKbq+Ej%dka#|S^#A*E31PXe|=xN#7(o+Q}3Fn&0@e}{+r|q_dDoPjR zqoIEkJUGj-;aFh?=2hjuPp1Cu;)YTf_|g9RA=iKXRFuWfqsu2!E_Bwxo*Uc0+x;dt z2Zk4vRj^(a}U9JqYPj8ftxh1J>T%bD%u z82W9QU^;AQ{^8GM#|OPPGFn&SM5n$M4MQ*y>cF~>pp@67fcA8zEGgB1{&byv;Krkn z*tiG!#%Z!%PV*mpWk`qwjas^ef*No$fWC0i<5vIcZD3H_y)av&q?hcKz`?#AJ~Iy% z&b0lf#ma_EBR@7YqJyL4R*olQ?j4_bF$jB=Y%;^&o^d-t!;LaJTBkHs(WJ*(E}DyL z_^}}%X5pP3W~@EN?c81tBgyuZe#u9HB#p2uU%Ji?ZBu5IGfZs6t0r7dt`Nw=h^A4< z#d$7SE07r1OSB#<#7Sc2-+GP(Lu>_~ZsDbg{^I8#3AzkAvc9ho?wQ14VjQ_8Ioo#{lw=LAFLr!s4{X}Lba;4 z9HI9XJT~_syxMW&w1~?qL{7mx8P5dzdR)r}@It=x?Ktv>jV#FXL~YzeT1;~|_y37b zj<6b^oDluD(Fd)h$@qMox$*iE3mHyl!PWST(#63NNp4EYo(3=_9VE7-ME6QvZmzF| z)9d2EW;n2oV3`?Wz3eL0n8Qwi^|A&%I_YRMoUGc}Q;P54zxX51AZ)8ZxXId)+_H5y z8t#O2`wijM6nhTtfsJu8qK}*sXNb}jv2o@DWj(|cFV7FB(d8=OvE(WdY9Vj-=vXUQ zfiqAs$vMHwrvINDZ9hqb5vsAq{A}z$HRNG%nWTh7OAoTgXj)ZXfY-xwb zZfhq|$P-;>5{>)^hhxQLXr9%yZ0&k5N^N*lxL~&nNReGVp~pN)2xSNQ$Oj@;&0=Ri z9=Z}+V~}H%PGbHXyh?PGiOVC5e~DmtlkK`n)nX(!lFEl?`Iw~OfSQ^e342LN>zbGs z7@3Jsy*?iZtWDG*7C)pQ#)LC@EhhbIPO*E4cs3`y+(;kN>28`}b8SdbmcqEE<;;W)Q=>OQl#;d^|<&wakEac?GR1t3BK`B3RD{m*F zql_N(aI^-jqyW+Mjtg~xp{0cEb`D`Fv?mQ|1V24> zYx}x+)qZIks4zhVdYD5Xs5T#@Je>o}`VqH?t9J)DxDc1v{`&*6{%~1Hknhf7Zzdu) z2aBFojva$AAl#4mmLjJ@H$-8KFTecn4c@Iy*UilPbarTUakyom)Fn@8JvyiP-1Hfx!rNpF@@q(j0)* z7XS6A+akLr5@5NSnEzF_nE@JDyHUcK*FcL^#xNY> zt-?IE9-ovB-n-6o=_^x0M8-p&SvX21KgLbyWm%&736AAQrFF>AS#ivW9V1Dc5$b;3 z0)v?R9Lk*~5YxIiv9**``z9soE+OkQ-fHf58HlQwR1TRi62J{8GbvB)G^gw>vsH=~Gc_hVkYQu)>GO>zgqna`kHW z6isvg2>Ygnvp`j|Q`phpg&T=OI2r6KYj)q#NRoDsjZuqRP!KXKLnKV$;n@vVj?!V4K>doa_V@EciFgnP?h+~ivj+rH;)&e8N{Lt9u zF=$h9F{Wl=`i;PA?D$#ZubW#!=C<+0btIs=4He~WsHEV~IXbg1$=UW``f%lkvZK@NoEZvUcv|SrTwAw=A~8wCTTI5qG7>+2Xtk6RFOn z796+xX=QVgiNRYo*2zq3U0t79pWls=SG<(mM#DhWF3T$*BWjVH2dJ0X4tQ_W(AyMC zh{3XHjhGl^1{cg=q8yd1;C{E%z?^G*PV!=N`}E}g$f1nvR z`=3|Fso!@D5c3;5K@Ubq$JfMC9{73RwBZp{qh9*|3cgZ_YF6i>mjFL(6Bxz4ASB59 zA5w6_IvxHOr0_q`Siadaze$3Ihf2|AsD^eyY1c=PM>~+3!~cRD8l~}fAjNQC`s32$ zufbt?IZBknU|8e{@Bb{7k@-S+b6GQTUBqUR#PF-Y&GlK>6y7GCiwRvLCo5=%b|z#6 zV>s)IW48{YYIas~xEeEDOq#Z({0l;25QM#@HXNa630FHxeVpY#Cxwd`suvCp>D~!O zXX`WOb^J{;w<81TLxQ=*gGy}f?yQ7}`{=+W@Sle<=(V;idsnE&wyVuGvkwX)4hQU= z9QdvpEQElD5N)Exz(OSu60y`^A`l=kK z*HI-j2cz9JGvl5A#aT?=?6*SIPB!Fy0bM%Wm@413g{#6vRt6b-52eqvcAEV3lNnD&RS zfPZ(^b7xSJ$=!*!TVit_<@ZWeAAzH=i-LH5O)N|WTBF{l_o5-@kkC0;a`LcCZ^c2t;iT z^j{9kP!kTQ2KRum?d|fci;&36)rx2owA9c}^O%%gKO&2Me4qG(#9R&h8xQ%jFH#Ob z&xONbX1)MwdYL5~$s=ioXCw?lGYpc%9FPsl#R#dYhatgKkhW8k851QmseqG1OJ+b+ zWzp_czd$vs5$is>m+v8<*bBJwQF2sa3)Or1Fz&mbW9U$F%yK{HrjHjAnR}oxM zX^+Lk?E4Rgf&%uDhx>wlE^>sYbksCzjfSvqi3eT~C;XbjQwSJZkuLRwy$6D}Q$$4H zpsfZYox5SlBOBAsG!+&om2vWjE&kWpjJ?9Vf#sFgMI~B|PEi}w{N+TVtHM2`wW*?% zkGO&h1&P0^Id6?*z_N`5+LErXm+5eUtBI0PW9{$@1!T~bbV-jjz~~Hc?^2xZc|70@ zA9#V?M!}Ug4v|<`WuylP6l7L@=!Vq}q8xO*WLW;0kVif3=(HT+Q=iLRjJt_nvnNuY zK}5_|&0x~iB{QBe@EYcQ_Z?cYbStvSeZLO_&LW6+Qosg0HBVXg({A-?7}le8rxk*L z-GBQuJ=Y9!ef(NFkC8an>iU_)ZvlAU&ue&P^DO8$U<#6&YY^*lf%6AUUkQsy)gCr9rRq6Q>mjebb@pE zd4i_`GMKd=LCpO=@lAT7c&^`HVH4^e{p&75M@~Gz@qG^LX&?R!!sos4tDkG^7PxoE zfEOOkBJ$OWB!;>4xWm>8_%lVSoL<=nXb!kdZFymT$=km z-(@zezF^);hHiAq*3;|aPRAaLIAQ#L^t8h+%DEXj-$Zk>{EY(>maay1q8+x}c~Ucp zNQ_FLMqs?Z@HELI&w1kZ6FTTm0ehdV#E4k;Dh3Y<2kEr4aMbwzB3RKW^8_NNL;~-4 z0l7NEGfW86Tb30p>|12vmGqrtgu8Z%b~%|U-5>(*`biu8w&RW3uB%RP4>6`JClQF43`82F;q#){x0{O z7#s#LKffg^O`xk*++}Ht>>GP0tj(wKMWl3p+`lh`RE*4&;55IGiKCndmOpKff6|HI z5HRe?)S^KwX>`Jlul(sk$)>*HG6L+4lzf>2r8yXp0O=?-bh&kqy;P|2M5wVGY1Jx% zjW#pwSgw2JH1smA+)(Jbw8sJw74CXNz+cuTgjj3wfeWwnG{M?x!ss1=NaxCMO{ zARCXtehrpNn{X6)K*Nol#mO)-ZH&t33;`OrIQwl@wX8^gGHGOFS9-oLk1Zy3XJizNz8RCAt$D`RuzW?8xx;IsuWn|QQdf$V+n0b>sAiZUd6^0;bb)$`q zbWyR&wgay8n=uzg&c%AmFm3 z_B%~u%?>YQ>7J7ckxe;jBR`TRN#TeOXP_2XnB_Mp2PN|VeC?+Kl2HQzt)txbkk#y( z^CO^AT(h*sV-ryOQw)cuC(vMu7XNZRq9x3!*Lr@L9o^`nc}j+7;Q$9*PX~T+>_!XM zq4plN_%Chw^RPpYA^)t|3Do$!r9rth*xO4nGc{28Me^pV>owEa7iNNaR2&-eOgdss zLbM!cigu1fH)1^RxcX;+pk7e!*Fb_)Pb6Z2A!M~Nw2VIm_)UR{1|DqzY55dss}4

{^7H%%l-DeJMH417V5Jx>N63yUxBP8K*k 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�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 V?u79J0N}^xbu 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 VP)rX+zKab-ML|=(O4jWA{{r-IpBVrE literal 0 HcmV?d00001 diff --git a/docs/guides/interactions/application-commands/slash-commands/images/listroles1.png b/docs/guides/interactions/application-commands/slash-commands/images/listroles1.png new file mode 100644 index 0000000000000000000000000000000000000000..43015e203c1b79af5fac7729585540cdd22b28ee GIT binary patch literal 38224 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⊂kc16iuMeMg8%sQx6aC^_$PXNs@#k{zB=NL{ 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

E+-!R0d zVZ)H~Eoob4#8`}#XwMwiai4iSsnl8W*TO`Rll=5p_C?Np521R#gQ=x^4M3-)c*Mu_ zZQrH63mC()FFTz&@u&w~b|5E>WRH`3{xm)BBc!sKZ_|s&aDw+XN6#@9bXos10iQKv zdSXql;t@M}MVVX6+aK9J7H6!)JzNp<@5!x(;l0UXU@X98xW-6yW0WWD#^g$%R{^(C zgW-`0h$iigeN--NinsDjUIjk5TI&K7t9++2O$&lITR-Y=5_z5Oe*&MMCTbnIX!v_3 z(l68gKmQ9~#(M(P9~n6kZv_LV+8G&KnZb@e#v2{YUJdRJbdl-gQBSNiCfqycP1O5l zgR~EwnZX#_j33DI5w}UX)f}j%@uBwO*NT(AO(GEucZ?r9NtuEoFSt9}TJ(nUX2iz9 zrF@4&1#H(fFy%EKJgC1_HY6J@DUjC?h!r(|>YOM2JtMi} z4Z{-O?XsbuS2=GPu0H22-1O+!mjS`Q$$BgXgviPnPVmutRbP!wF`=;G~^Rsn78H`78ZMVo9UvjfEP5P}j zC38O>r7Y*6moQTddn#v33p7g1;FEOsN7puz8cftcl^qQ1OG`6l%%&i3s)+l>V>edBqyC1%(eWRzb(%uJjuKfe$MGkkZY}JTg*Qdqoj+O^8=~xM< zI*R-eO2B5WOmp&e?ZJph2&3kNQ@m@3JEHHax}BP^cqy>$7vqLpFYw4hdtG@mnULemKFOX@B1z<<6hZX1O4Xdyzk+dpBDsDe z$imxros>+kpqg(IJtiyl+R?k5RgkR4I=!OgxUf$%*MEmEEST@O-(< z_F3PZx;oLLjN8ZK!I6n`0_G+1m<8s9e%gr4t|0{fMU{P_fPO)-lU-qb85kt zMA4Pc0*-+hz<}g==rmr&U58y#TdWZ8PDX)N`nl0phKHTQnhT!X3*8p-$gfMSsek^m z(8uC|uhhm)vDJXJbL=SHXpD!;k+v zs>&M7u!BjB;|1|I$IQP>Lpkh}EnI5o2wMllJn%z-gtICS4Wanm6$oBL6_u$3fc z@FI7L@kVmLyv(-cU&9GMz^%xm^+OAhoJ5j^gYfoHn~?ZFmzw6$*B ztiHMXcjUt#Q}Yv%2|2Xj1FuIK@41z;9pSZW-NdPXbqm>35)y5v1fPP+#~Ba}+368Z z`}i)wS8o6o%@ih~pSZ#K5qYUUD&0F8se|>cKBjVd6@6FfD?N=m92ok9hbk$me_@f< z#N?I6{s4-k-x1c6;`*|H=NaXILFN-#pJplBXYr^fU3O8q`3LPnFhz3>%jv1&<;B{s zDxd7khr(Q!v(n)0eA=XLh6&PcUMzP$e;AmuhtY)sxd2I4Yo~jgw6nZR&2L6|__$BO z4reJ##c}lH`$yMxVrbiDs~C;!<2JtoFpQ39 z^fEfE=({cBrS1OsGk@K!?Aaq2{sHG&x$UNOPBA|@XoCpF*0uR!u`q3Ck*%pYjb~x^ z*7M8dXVqa=oxXGVaj4IWc`l0RaA3e{`xSKf(N)LyBL4!a{&Y6$O@FGH!^2?Ur)ut= z-?6m+RJi{!!UyDdpW$ZNlM+>`Pg=p=Z&4J#!&QIUJpLvg#%eCS&1k``3060$dTi{y z5>Wk-1@M4D_FL({Fr~lpXJ59rf62a8M!{>$X>znZtv-mqDCS>)_U3ksJs%#hA)E5DcFEk{yeh<6;sn9#W$uIE}v+J&$VBMhrm|rT| zlKz-uRuGwU-h_33y6_Kjc%=qz6&|H(={! zFh256EI`~~`j;g5mud2?1kWTFteYAop1$YZDuMj<)`DM5K!fkdKStLGosGy-;UE7< zApeVZu)hE2O{cOeBzTX={A)OW@gc19H*<>f>+g({-?cn9Udw+OEqR{#O04*r#^@8# zzb7JD%Rg^gBQ{f2dX4^X`0M^_%yF(?imMt@uy#D^$7DE*nb{F z^p`LAgG2sN(`=7>@6&tU_#37^|LVcK;ETjS{Pj2B#2>RndOj`BMY&Ty&4d-a(iV;V zqsr2szvGKM9*6j+O_Sw(zkQ?j$}jHy%l{u-e&SdE4BmbA1EuqogSO+3%Fln^x@qP= zM~-`fwcLY)CVx+*`b!4jdD=b2bit6zblKc?dU zeh2^4f8O-6JV#A))5ae%>#w-a#^|S-x%vN6kIoD~Ef;&<29lB2x#&Facnkk~kTj9~ zpEvE6c?UFScJQC#`F}E?FfU#%oL~PprT!-c|0Pp{uT52Pid)Hz{?F$A{f^q5f8O-} zitAq#6#idv{h#XeUz*_m58|3Xzq#=26nfUMJ$*WU#*u7u+IsoFuOI#`l25u>$)x7G z&&?l)ZJV5}o-v*cL(iZKXSlvtBB5{cIGy0FfT~W`(=L=ZPo(%zlWK3m&O-llSH3E5E0)@I zO}?z;-eHR3AGKotY9Oq#1V%jKu8gV*4=PObZ`>@q7-gGDa+~53RP*%md%^6VN3#4U zr~i9X;&CF90;=njLs@?e*6iUAG16c4DgRous|Ebj7lL*Z`g&`@S_de}$v0wHTJerZ z!C%q#Ki6R|+tI%peQb58vKGL zcM-Iop#D&nc$`LPrA&QZA@nc)jCg+13k7PU>TWMga$|^z>&&1(5H>ElCJx?0AlhHW zaV-SfKTJ#!F^QL{e6(al?8A7&V|bG9aazWHn!@vRLs@WJYLKon4vwf9r7qhS76Vy` zKgkKJ_3ZSl8)ftx!7KQxF_Q187Cu4T5K|IdOF>$m3hf!CX_v5V=Mqgm!*CxB0e3I- zyq8}@@F}QFpy?MZip9R;bvzvXiha&19{|Aa+R9b`!v^q(RyqxRbEZcqMP~Td@bc zs=|&2tc-i<<~oZE@X0I;2$LJFV4zBV(vv4M%y)LA(NM03P}iZwZy#8-*q$rSas_{X zPjW-)%%q-$?M9uJ60qt}((>#ZIkn`ssDZPg>!aA7r=!>jx^}PmC#+d^od!~tt>eik zYLT&B3R{{2QKzA67{K#q8UfGSf5^J8l&l%;B&roy(vEwQ(61)MRin}IR^+QgT{)|k z%PDMi?swx(Cb=xZ8dV#kLUPGVj1q2ZAKdveK>0@FqQ_d7Bhn(%3Qmi^poA>9j{IF9 z{O&8C)<7A~5w_D9egv)GG=ffUGvm{Q=ZJJ_{0VGurGcm4k@h+Yvrlb^MY-%CmpBg2 z#2}U~;iU8YYDjU$*MVpqo~F_5<_O&4x6*#W?Dg+hMhUEjPj#13J?J`}taZ8=Vm#Vp zO0-C)zn5v1ppFVHl4Ng(^`R+8E~Z)KaRNfGrco7}R1ba4Pq`Wlk)Y>hnuZAV@H%MwD*Ek0 zm(&T|)yX2RT6Oac6aaYwprMaGLF?KRv@-ek(+4Q**ISHt$OW!uvGBeES=eS4cB&V$uh=0*Iu zRo|HA`M@U{#%pxZGD?8>$_P+on*VZkmjCX>zQep)UmCe^#jMFUW^pG)Tjl?zqR5iI z!9!zDbkU8T!%}$0DotO@9NE4g;j@*x21VFhaLA->%3I7p8$}U27Zp^$5Oh4L-CmyU zhr2n25m~TUN%lxlc{V3$6GKv1$ zy+cgFkR{wb$=h%;A}C!Y0prWyqYd}7Y?R#TsV|qAnq+sZmyw(n^rShRDZd-MZS9c9 z)H>>)RI`%U*D_#|3MZbx?`|!q2c?4-!5g9y)WK}YPL%Nh@xegr9z#PuE=%XP<(tFD zoCKr$Ir-Ig)Bsi~P1_SBi*-0dJkk)M3XAW&Vz;U)IC5gj*{$9!l>S;Cow>fz zL!f)F=ErIM9a>S?j#WR5PuE-}V-rw}1*CD=tgjy<65^@*PTdwU(N)``7~O{_b3~Y) zTXbX4Vx#NrGx39P{qg)bTC2@cM(P0Q?eG{uBWcz%Kd}DWAawhbl6@$p&}NNq##z!X zods>N2_Z}iemd%xicizMVlB$g zOBX5Y=c=M{TBlS~d(duLK6}3(jWPN@XN&1h5t1p<2yj6m?2C)~5uLmCV_-`ZhS`)Y zBG2V)!!9&Qw4>qlDQ^7(;Lt7F1$`j?Ts;{H7%Jm4*R2Q55Z0cnp)WdCrqT)@drbV9 zphwTTpc(#0V!dbG&RINUr_(tJRW#SBApqW^e}Pb zUYFr-JD2Ur2B<0=C3rHvH|O&pOUPdh42&^09O4D;$%NF$C$Z-^v(qhPaZ%CppzY>m zshEb$y3m$K&QC|ku>SVKUyps1)?3z}W*68==q)+jvCTI^b@R;07yO_*@COSps|}YC z2p;yJy4o{r(U|aAE>~CkBKwu4PV}kc$UB~SpPU@v^B$l>x{W}A3XI6-Q&H{<`goQH7QQmqtFwu6%-kqX7bxT}l$wg-*$QylUJS$u{ye2G#5yYv%srOR7 zP}vGs+gRSSo-iHYs&YA^fGU!_EZ6bL)^p|kpuDanC$Yv*sGXAwK3*y#%`6ltvaVj@ z)_^POhkNOGU+Wxdn%xPqvif*WcKRwWWq1bvoPTdqj@|Ozpza%A@szr zWxHI&xjjQC(T7iRmYP2~c9ss~rEW{8*UFniOY?Y_zb_X4j}6(;T1wXT5PkA&rq}^4{g$w0KQ- zvQdJskNkH?k|@e6=hIH#l0ttnFwXJS*h~&{li=|N%JLZgOl&Rx`6@bV?QKzvzp-J4 zd7e^$higV5$+AN4+t+L0nNMyDsr|yx;!Hh}(L=wtg zH;AttjoMKObavwOmtex&%q#=7QTLq9asz4;atppt1o|s~-C+)HsuNlfE$&j35fm>B zQ9EVIaBj%6+5|$(dw7SeS_+xKBI|LE12v!k!;+D>Qo{omu5=zWrHs0vo#+b|AJv15 zf<-+jx8%CCoU!k6v~9=^OncXn%<&%4B?`88X%Zy{rv0Bb11twoPRn| zur}tICdBjr#&+>e4%(W-c9mz?djAgS*3zi$4iQ)L(gL6CW_+4_^G@TnZBQrgF#zaL zDM`WK-VeOtG?uQ1MgiG)Xp?GV1sw73z6d-EQM00F97C|QP+M4=^8w%Y0th-ZfM ztyt?gSE0O4S#kExIWHxYMqCx@Gzq@-LJw>))L8fa<>hMTrl@NzKl!ks zQw$kNtGPmuLlR4*#eBM+m$0bGBzTOI?YIFe6eb-iiml>e|v~ zuC_#gZjFbK7ERyY9)Oq|R&f-UinT+#-&^elUHUP*C@r*l4 zR?ulh+cS+SE{V3)6kIk}YhLh6zPNE3D*ID-0_`vR+h5pdDkU7-V@&?85!R5~Y{0P3?Tk!qCNumU@e8^Y0Q1BAv9a zsMYlE^J85+=3idNaDIX%Z#?#>Z`)YHDR*(!M)ydGBp`G`gl&OdY(}=A8~#Vx+w*x= z7)i_|TqB)-nnQ2gYSRUzENcead=Isc@{T&_6te7blW`e$wHaQS2%O_w%*MES1T49d z?v%LK?mJ;5u}PHB7?lEKx(4ji&Y72)`1s-a{7lM;#2zJk=;HKwxzY)nXe=q#NA9t7|T$wE$l-T#nUzL{z$ol)86(s ztQakrof_W&%~OsxgVL%wfeSnRPQ?apOtlgfk)ZOlEc1>Zwp(w$B!d6Q1yCTORb+XC ztgdl4wM`cZNz?lb>a=R+uI&W$Pb;v!T+{hLXdWM|3M1}DyY(kGE#1*pKjSU(e96m` zI}-Q|*;rM)D%d?2k*h*!I@xIQ@aR}HTjKW8EA5La)QC~8dzyQluTA#HqMlLl+)gkv zWWT96+^x$l$9xS0;N+_=VaBDd5yR+1M<5S0kMkpwQytv$j5_qMwG`IHc&VIbRSn%0 zov)Fj?y+vWEYq?zwf~`REc*bN$wdu8W@ z;$7Lt_evtTY9Lp3CoQd2-;s@`^i=1bK%QgHQH0woH=`>}k~36&tBP(KrNw>wk0g4+ zr&EiX(8;30qN)dkue0tNrUZ1mWc#403##1hjs{>KOAU<~j4K_}(A*716*n}{Ax6i( zf)j^gVMk@5&i&CoM%rbLuls3*Uu`aJM8_oHO{*M2tM##xSDMUV?660~8@lfKx2N9R zVu^ZeY5+%>N(*5_R%(ban@8Th^oMi-ZNkg;p)b|brd&r-LuGd2>7-aKP;(M06%tt~ zmGPm&MmTL-K#Eg;T&p{Xv^8TN>pLzA^}n~Zyfhp}7VWp$mwoaQ^!i)1^~C<5$iaZP zXh)B?amF&PKcY3GlRmcCYW8?Kx9E8oV})l_`fGd0(8+wBn|}^!{lUYNd9T(>zo#ti z@kg@tgzncmHk=tP^mD%ua>|VO#)l%;A1Do;` z{z7;|gE(8+lq@H1@YW92&6CNq<7i&IjIHL?axXo0u$0W)Pp!&&YCR#?GSR%688 zdmy3>;@MYnR-q8}wI6mv>zLUFOGWW_H^5 z98X5R^#q{=SX*FOFJxs+riOwYsP_KYA+e4=9$8azQ{pTAZt7&EBf!ZYoZ1%{;qTfO z*N&Eowtv86_Nd>KVq*~6gA2+T2NCzxJn}qF*-N-RzUOang2nr6J=3%K#MyGLmcwQi4Ay!(Yb|8( z9T6PzNVzxgw*&tzktqC7y!eu~JH^e#LJ)eE?AKJAI(OtOC~i$lapQD8(7itnk{8v5 zu-1mgs5of7rFXL{xV^D!P$Vm_c9-Vd#VJJ7fvN@r`x22($j^D6HIw;a{5)G4KI)p~ zHqrU8UY6E(z={>WU58Y_nX_A<0aoO7OWx92=FX2N14G{%L$)v$uy)t2mPfG+uv0_L ziRQiM6>HCoV^tRixaaQ1784E?i-wZHP5cp6(-BJh(1W;VGMrp&83JTWTlBW$evRCy z{LQ4ag3P0tH^h3d^hs8w%)lIPGyeByUBwHQ&8Z^JN%muJna;#ft!h&hW*mli*B(Y! zu}L`WP=k;g|0qX*TZlyE0|LVxLyHep5e3 zGMbHHp$D*HRdMBDV_t^vb+rJ_)Y~Z)k34D8cUg3z86fKE%avL%SBQH6_Ep%v=F=KS z!}Sqm6tT)_Ox3OwlKuzT9;AF=9-qLOFPosLx+z_2V>m()_L;=GZEmmTp(0Fjw^$-v z)8ft|GqqQ<{{#2;U8RlDQJd_o}zw_)Y$bowCUfL<&GqwgyTlzJflKFF1v$`2VKt%CP$!`Ag+Gjm7tjh<#Hsa-NHk|v_0#=?I4 zfV)Qhn9+O1O{%!X8w@6arF&9Wx(Cy@66?R5&7_JTcoX(#_r^r+h&AY?5<*SfHO!8$ z=bmudNjah5l;~hy@8zR>&ZJgbhL0yzN7UhtPH%P?M;naBnUJ^lGOMFyoV>O>^1s&( zeZQs!C3rZwCZF<&x2AN8h+5cUf9A1nnZ$hgU9Gbyr-|h?io>izksI$;72E~|v`3G7 zDlm%{rj8AiUInHMVLDmWT~YOey>*g&JUm;8?w?SpPnU0swAvel-}m4Jv*gv;N5~px zPa(R)X)`6{gx}Ijmh^_R8By16YR}K!>XAWiwZr`xsG$i?Q<7Ar*%n_cojzE7cAIz& zu1`wt#QQrULsWAJVad^z?L0RkA*d`5vIuLD0C%0O+!enGG5vYK;3w1a!xdScX=RKN~(f-OjH=;=GKh5*FmJ&!(n4ANHKy_f?by;54Zx zmeWJ#0B%zd^fkM)-SGyRmyXu=pB4db@mi7!a8W%7N8JOP83x8(fNq(+MXo4&_4>F} z2kw?UNbX{KIHjZ4`{88HcC?y%ROK$t$lJ?8c(yVoHuUWM(5PU4E#6zSJ}rL2=O{Va z2l~o+dte)FL1`q69KA4`>IBNBkCrRg&|vkT(OgRYYWcK%w8>i6t=IRM|5& zS*7s3k~5OYG5wR}$+wZoJcLn9u*E4${hL~w(w#;rSaxxbD{%l@rEl$~TYnLN*rA5b zqWJn-+jefags7|E#Gv*vsIJ{wtDeu-LkNphNDf6O9&5X)cRRulXLpPDa>0;jvk@tb zPSuMwiU&*-!c%p1DVsV}-vk51)?uhOX_BO7FxElWWK3X6tTr4nQ4dk!ebco9ae642 z9_nk9{5*?L`fTA-Z4dYT4~lFjuKss1yuItL@|1(TH}LQd`P8FgGTkEaTYTnr6GdDL zIU*4Xjs}hHT28_5X6r*>={tdOZ3ls9CmCsp0MOk%f61>*wv|d#s6eZjGcUtszOWb8 zVqznK%^&Z|y0S8)f4R-~N`h6ocupGaudtud*L_(}Ug0V8T#BbOhHuUqza{+Prc3qn z(`YPIAGbz;4H!7~+MO0?_5Zk;OzlY~Z}*aK_KPz_eL6R<``ReNN@#b7oFju>T{b}V z?VRwHMpMfe%IO-GrgLNo#MZTR!{SCo@DPan_L-i(=#hK60On*f?GMZF>Y&7t1py-cfwYC*Wt zWxgBj9~s!JEFD&l%wVa}0V9KZHfouLD65T;{Z@HVC?&5ke7znWPMtS4PUx56&@UM= z7Di+?8RD0Voo`k%$y)TlesU*dv#{=Yd?a2*Wnf`MbwJm1d1~aNR>s1S1YZMd(HOc~ zagY~qJ`^77YFW>50S~@+ zUp#Uum)Jah>eCMCxoX7u{W2Rnh#}QZwmd`stXKwAo2#DN?Q7ucahJjIP-rK!Y6BCT zPVd$yy{SmlaCf~SYu{k`TJPlxC-niI^*oL@f&eO6+L>R2`Su3!hfSOL*gBb4=Gv^y zp@m4T#E+vud76qi)7 z<%m_Iu6nEP40H|uJlbX>xtRFtq1z?L@g%X6QVo{vg>oM-chuMqnmw=H2_X$@yA4dY z3d2ZTb&b#dM5~rqvkleO+e9VM=m;F{2IQ+tjrs0Y6QN{JGUaAx(Jz}8=`?Jtl-C{M zaCK?344k*b;gYVkxS&5vhWi!V3JrfL|Kzjg7mff;1-2+zI=743>(5Q}K4QumI%Zye zmmjLRVL4rmRsi6hO&#Y$rr&b?L>y_OuaoEC@tdh*cHa#T+(gLhGh5BT9QlG9RzGC% z2+y9G;sPiBjHk+d>$aJHvy6{H*}X5=oiDVizYYxA6*gdS@uy;@>e>$@u$2_WARZd4>_4p}fo9#*dk1W5VS_bWg z@x#z{kC*p$Qq*gCk7|h`l3si=6&WV|3`$>q2l`(ySNs-v~tjK`vvizb`OmnvkJ(tKMA2bx7W=O36Rg8iBnc=NMLZ&^1=y6Z+ z`aK~tNsgeBa8`5wwlUSsF+xGMkwkbwTg<#z@UW&{5j1GM#b&I^zy-6}d)M1qKgYEPXQPxX{_dCW< z-uiBPeln+CiAzQL(nv}2_{1?Stk&AUZEn)w4l}yL z_bq8Ped;NKuRUrHe$?Ck>7PO)7jEEA*4?iXZ7MHmJ@X1dtT z+KRWv(zY%*r1Hib4THS9~o zY3lV_r?;w_TB3Z0zHmPnkj-4&oZ3_)sFZfw?tw(6_ibA6lAW&Y2xY6{Oxb3d z^h z)Nm_2E6uUV<-u0f@M5o@Bx;VdRJ3l*K#9s&H~{KpfdFybEbAdTH22+uE9ZzUB_EXj zeyp-TNoZhV%=M=C8VvMBJQqg~PPwgRDY5;*ZZE&>Dq+`6Px&{3!@b z3}^cUxYJbzS}4eRdcV0m?TnG3)5Pkz^`P+Jfl=FCb6tLZ>ad4!0vlrQy0)2?Mb?LA zF9#%(;>ZOIvN6^87$)zKVxIl(K-APn=iUyLI~TrDDS!2rJYrZit7^(rgbdw2a{nZA7uR(mraJFI`^ zs~29R@{($4ezL55P7>@&yPqFVUSL>%pm!Z49T@X*iF&&XN*h0`e~D8gM9NG&wq}Tl zV|-4$uz{S}{7{rfrLr^2g1KDvZUUw8E!qv78dVKdMkPDAF_m$>7M;AB6YkJ9`jw%j zfVjJ2)CEAOk)lmo>~}kb5|^)HB4p#3mf%&PH}RHS-8)N|5|9TV4|Qf{tAUvLdU{%E zvx2dW50C3qv!G$hemozM<|ykSWZq)JyCNdzquTi-k;;^-P4bS4P3AsW6k9K0n zE8_S;I!~c@(b(Oq*m%&B-Gc^<;2w8ns+SaOucU&4_`K~q{wSu9k6W3;F5O~LuL=YYpR(mK5L+WZCU+4?R{5NQ|q?ycB{A* z#Da7XK?S52=_M9WYNCKdy0jo&YG?^tkq%KrIw496MQZ2?Md>xtON2-_^cqNj@W*}5 z9e0d-j(eQ{>Au`NWMm|nYtC=B^{sEVtit!Id=6xtzMWT<*r?&v0R>-g#*N2tTLPr( zIw@R#Lf`aV;in^V#~;|T8ult%OUj$@6WsO=X74t$i;#MIStmbSMkRZ<*Wiq9xF=)D#e$KtE z-SP&`Q91p*Q}tQXF!E3mK~>&i*^#25$uf#cX1Uu6ub7a>Ia7bg1|AmP$s)^gnAxxL zl-m-$8p8URG|{O(LF?|OU4NWMw6djC%~wpS&Q0*uM-2y$RyI$mHcjMHlO11p-3{gm zcU^UY-LY?{yOtVtaVE($wsxm2w|5R+t))WWYqu_}@>VNJAmx_LFNZT03cKuK;cc5S znXaNt&9T)prSY_DlM;%A0N0pKsIa=Gzc;OF3cPp54M-xc8OW&~n6EwPk4cuhKe1<$ zbf)d}Yw9QFAZe=aJkjK8*+2RYyzG~K%a*ys;;}`H)j+d2ob)KTwo;GkC_SeS8z;uD z7fpla&>`_H6m*9!S*mMg(Z;^~nd&Z1txX4}sy{e2UgkhSak< z)itzG(mr&F#315$D`v$0DZqjP{)+`NGH^NgEBMV!o4{VXWcn@?GfGU4x~vTvv1~KC##q# zAh$QAEb2>qTB4^k8E^Sli8vG9RoHE>pl?}4mP{*1MsFt5vS%btd@qnOl$z3VOC&E}u1+ zb`*x;*>z-&GO^{WrMMsH;X^`(vf{V{dog>EP~FyxqsPk*T@+iUL2@4UvYfde;~?*< z9s;zbDTG1n&P{wl?w8{pjyl2~yzLhO%7$T* z^*I8^*8ZJi?PoKzIdiFb!VU7fCzh=2m(b0})!42+q(H=KvMfYqyAc?!87k+BH&$Gk8%gusW---hfrp z#!Y7@c4f)VPBq@CVQ*8u?zT`%;-ygT_ITT*uAi@-p-zU2AG>SHJOoiGj z&RjD@-&XhfGKLiy|Koh!3I69oHYkvg-C~m?C%I(Pt4gAhez?d}NOLebW-0%%zfG(@ z2JWG9KNal!Joj3VDNW#3sPPo`mzac4)O~k(JL(qdKdjFc+~8+q8AW}&W=pQH-zu)u zoMN~$*_1VUG#?wNr@C7{sA?t8L+MDrrncRuPNHp|>!;-(-MOZf5Mi>(QFKquYu^|U0Rgi_JQ1MZ~MKaN^{zN@Ex#lbb&JS_`L&|W^K~$iYRoanmk(k0-YpkT4Ra3 zvIvJOu4dL8Dbjuh4@l(Bae0^R=33|IylaI#%blC`lgoA~QIr&AupBOP@mngrVfEL4 zBHaI#t|upm|)s`RRpn|=;ElcIN_cp&oqO5@(k+5wO{)k{u#xdSagKgCM9 zew$NzSrXMzC1Nw;F9fLlaZ+vCcbKr40Skya|M*u0Mx> zZ(E`mK5w@4MHjyKup};G%q_LVTx%$!n$BBO`^EUoUgN;Q)SErKH?x6`I)~eSwD3dX zY;Yi4erEm4Ikz(n{wx>~b&UDMEPkZDMeMaBJp$Th$1egG6cS(Hl3ZW&JT^hio~ZZ zYhK_$I?lGy%k_}~cy*8NO;+x!BED?IH-?Zii{njNNuV!#8PZ@7+a4$%Cr%V}Sb74<1uKZt}%66ZaAp&}!4rN`@EPv9t1AzLJ z;Rb+F*AtFC`z=3{fUNtQ_2lBiam?K=iGHBV!Q^9-49S;t?x0wB)t<2cj$5b|l^I+8 z5=kxn-9x8j$qO<{e}s{a&kWHSpl|?!?6Kn^E=UYGT9c z?s1l354Elxk~Y9)Mv@!9Pu>BtQ5~g@CAiRR6T)U~n*vTEK;i<%K4tTC!c<;@ zPBen?0;v+=W}eK75sBq>+SRVLF@9{y8%$egrCA7GJP=B=K+2~11;OhTznv}8`mJ+O zBA~&}1(^}zH?2^uWpez~-(|8+&8PQSfLIbj^2u6g&lMbtSBg0IAf(O^QTAH~tk|)3 zj{!{F;^+3R3Vb0FWuJBfp~U zO+0WZ3dWsxd|J)qva+5$c=^Y!Z{7YyG=J*Ke#37wMBKiiQ1-+MtM3w%>iYN(6|aQw zHQ)0f`wF-B*OLaZX_KdfodKfq_D~mmV#4v|6}z5n`^s@mwRC6+^w1?OrDf@q2(J8A z13EZA&0L87kfJ zuG|tV^Dy06N`SH~j*(RTNhUeqHx_Z%xr0!*saS0L)MQ%5m{3BsiSLPVK9(j}Y z8lB6hf)jrGjr)zZ#$6+)3|{lqr`|Ho4Y-}EwVvJOkJW>+T87j2^3yiz7Qy+F>}Eic z_s#h^U}~#%9rOsq?$%>;qlr4YwU1wJL|#D2DZ%wj7j?}drILY#^L_3r24Xog`b*%; z559ajl5i>%IJ42|C7)4MtF1KJYzU_W`UocUZ5))s-{i(JHZ#-YX|O}zrejz`a=b|> zIuhr=%aR{7&hliuYP`V#2=R{rImZGY=6rcX6j$3y8@h$e6W_1aeb8Y_DJmuI4zPx? z9wT48T@czD&a!>=f?u~)w!Uv;5P&g9QCFSx^j>$_#RHB(vM!dqrZe0oDVFgmW3H#0xxN8K?;L}?k z?B1#M@Hc7nkTZ!QWVck2aLTB=#h@r)PeMiy*Sn(!>9IhFqe@adXcj7Z`BbwZSD9|OrmrlqXUUP_ zaPa6UBjGH)rztZQp`M?coI~<()Za=*;B~!v(vK~?eb7~mz*0{(sHx_LW;~5W7WLdTW*_g}TfUchOm?laTUN z5U*`+y3%8t(M%7283tfiPM#ZNF!LTtiNE%Co~&i#;=uPV;?b(Qty%U8_xqIg>_GhS z&T`W1=i|x4K&GGPBX?_Ch1O@*=}$1os}6)F%l`cvY|%4^xu~?NrK0EY5rt{2&Cx-s zOI#r=>_sq0#|#&D5Rx~#jj#q)KMCpfTd3YrXFGVtM=zIMU<3VDz^^=feFq2ERzK96 z!)zyIW4_n32M0*hF_d;VjD#<|22VH`_sN9->eF}QhG`i!g{SwB6tktS&v6l6l~ZRA z=&iWuwV*#Y8V@!FLfDg1I+%D7>A&N(*jO_QHGrw7-Giswm^Z?vR^t-99MTx9C!iUL z67^L=V-|;nvJKmNY$;@<4_PCm`VNF)TGJZPOz%NE#?{HSuScMX;AXw5`-l{r(Fg=Rkz>E`!&f4$sInxdl!hVT;1l0_i^2GPNRl@J4MSf~5 zC81(;(1ZHFeS6(>{$6}%Dsrq>!RDc288AF&eF7PG-@Q(IhkmNrd{@bT$}%bb5=H`* zSPy_tBzkSTIGS?g#3E-kMV<9p<2mKjVwvwusrPoU|g;iL^6VVXH*9 zB(PUGshknCT5rMN!#{5R_=oQ>VZYa{H=VkatS#6}rj+&(f}ALB?}cPW#G|TmBqFr`h(x9=NuDJxj7sCp0)0M=6OpOpzjejfC`6 z0vCt-vkxtfs$8}9(iZ1lK|L!(KwRL0!}@Zaf$6Qdy%bkTk!lbB`6pD1ikcGNog;<5 z08@Ehk0Wrv%j*gk5Rum;>NAZFnm&s+ShbFCY3%in;o}%f4#sXOQ6K~1OM9k#%%ryH z_s30?0hswg1U=*5J|kEP+H0NRItkT`1_W?bK7@NsN16MT0EVIC@LO9@mU*x728@jN zCo9V!navWGJ?s1it6A50{l*62W_qsD$GisTG#Q6pbuW6OQeUg)7cO&2k**-1?)ph> z3tw{4u8GlNVUqP5rVN01cpW%R^oeWGgaU6OJ*_5UL9()x)#_5p&hdo1%Zu6E#Q|>5 zjIYZlyi5#&MOYMEvo)9{6n)3OX>KPWHD=QF`G)Oj2BU~%r%seQBs ztVz?~yo%rE;LZ%7eXJ^*kGwilT&Gs+9Lk9w3n&HpUgeg#SFnn|440kfI;T|(WD|QT zsCTocB|5JkyLwW{ZsSiY1&3}HGvJsgM^@;(es~|GJ#?wCosS(d5h?v6{&(p@)gtYy zvc6uvBGgaA64}5H8ry)i~if3UX^GC$(YlFFYP4cz1EhV)8=x9E&RdxNBQ!Qa&DCp zE!trpSwG*yzmG$aGYP#Y+sP1ztEd?q(?(s|tDcgJbJ{MjF?K{oFTBoG8`|_!Z3Dgm z=yN)>p|acwGro!l1+K;#-`g~G(uIN9ADNr?WJ(m~FCqhmD$ipg?`>zoQk6W`QBp-5 zmPX*-Zxd#=W8X`pYbpRL*BX`JQjWn)qJ$m}u}_27ovflJyc!%fx&G={(Dc^^aDb>n zq(w7DcQ~*E;;hz`xerQ~_DTN!2O*7J4x76#*E_3-Fo~^kEBlS6^`e@pwUgseVB=p= zH6qn&?7 z+>}ysSWaD7aK!Vz2ekBo==VmJ=iV|-ob=T2h3a&aH8F;m7% zVC@CQK{YR&P@mEh#DF=iV%Yn`N`i>yt%2o+v?|LZ6?$;_b4$-r1}&YxyNYiw9Y-&Y z!GzD>^qDz|Y>dcY3RpcLCX$QX-Y!$P=v8Or;wZL+tcqUqN=de->G(uOG;`aRgtP7= zPF}3<4=ez^vQu+Flow+sNmb+I!2)G#pizUFJ{s9daZ0i~Lq+(0ey5djj|{rsGH_H( zgW|X$G>jt=pe{L!_izeiewrIO?NYkp%@`kp7Lk(&HPxO^p(7C3Stvm%LoL z5nT^&k`Sx%(5%D443`%^q;iRflD8z~$nK$0tK4Ph!b+5_V9IT?gV5-z1toUS6q@BW z&d|$4*=y+|MO^X-YuqhUzl3LhK2*}wnXS)>=*sQ=BM+`t5xo*39df@MumxaQY}aSD zNd5MD^r#3$-+(UOVjc`0JtBm1w}K&nd7-M{8N!zV3ErW22nsGdioN2?&PAJh) z?UyYQ)oZldf>YkH##9D{0XzCW=;L$c&NWNNMFxk7MYB=mg6hBYwaMNH!5X(m@9OtX zl<*|TN)xpwtB>vu0G4LZ5|&hZR+@?^B8;r1s3l1oTg(+FKw7qqYI44QV(y^OA$i4KBZHq&w2eRa87!<0t zuCh2_d(Jiq*C35Jewn59V_G z%-?S;FE$?r^0a(vUA_QW_4n68;1+-~!DbVIqA`ry6OsL7?U%_<5=T}Xt7oWh%L=QO zyQ@0g?-ie04gdx(wpAnUE`p!`$n#cvL>yCAyBgcpD`7q_g$@?uF|)#585M0dYw~i5 zuA^>5RlzDA!gt}mmRAs;UAgF+wo$}F?vrJc^gbO}DeH|b5We>P4M7t43QK_HFeakjyMA*|;;lI1kh z2*=6x*?W^Ws_Gw3V(vkUlZ~-I(o2=D_J`DjtHB63PR-gTG4bWr znn%#|iZv;~FN=rbXJ?a0YL6P>2(sRo2G6mhAIJ*oj0S=sK{kI4DgEHt>e1PO58em=)wuWgOM+1(G5Nk9f)KjljEXzIT9ye{a zeQWUBG84Xw5Nr%J2irLad&h1PKh|Huyz1=K;A~-QVM?J-Mi6Osz6j|}YJEe+HV!iC z4K~OEluysrv&`8qm}9eW;>wj**cuM7uHBB58w#D7E`?BUo|({#FB90!r1 zo1}P=bqzd+$`HKTz%r}!T|AFZcJn;CQlCwgn(UFdvI0Jm6&?n!D$IFJ9r6`-H@BH z?P58)_XN~SnO4cowd|`EKS=-}bk(D`P?V`*V!NG3ELDD0CEBj6 z(=5Ta*OuJhjx*HTow&X3f863XwVp*OcH*SspDc^U%Sbvjk5~f^w-%2)^LyWcr{vmB zq#_i1YhALt`Pt6(GW=O^RH_T|zgk$~Y)g(=R`A^BDVv{&i?WSXbd^{MAa)NCgn1=! z0s6ooTucA6wv6pZLj``zc|0<|sKPVn=>M=B!TjxCrX-{<3KHxN$RrGT6P=2UPPdLnVkN-}b zXR147LyIG>+Z4RF2dr_Kw@*{o-ydOZklnA%=Ib{LB<(4jo$j`-hVfx}jS>YR9?HC; zH+$OgBZiB9^37ttpBnmJ6_v6w1zB_C3FyRpajfKY6~G^AL&KADpWIyFFbs?xF4vg=bt__`*fNmo}yduP!ip$cWxv8>1oFFl}Nh zKl=9LVT?}lHx|xi{BFf;n|PILCv{%Rz$~pWy(@@0_A8mB?b3P|#``Vyc4Pc%eE_gm zzX}&O6}4;g+UM(-LY?n0vb^KC0`4aK=B)6W{`WW65oQ3tqH+`)=KF!E_+n>r$@^qY zg1rAk6@3m|#U2^IXZ>fTc}&#HApYkrtr=yJ&FmPFY`nSbKA7{H$@KW+ zjG=SwnGq&;bJB%FUY~w^u{b<_Ch+fJ5tnu;q!=BV^7XgU$ z)sk9yDeZAVtJ3p-^@5Q4%oG#*^)~HQKcE791w%GZ#P9`6pkNX|D|p%(>e^&c)8-DD z72H5bY+d;$df^7`n1BtQ6fPG2v-!%Yc!o_-guwZye+uxwzVf^0rP>d3(gu&Ne^$AZ zAfZXmvAcQt^y%}gcOwKYM+kk${C-+cSy*e~6y9{DXSX(^r1V(@Ie`4logt0bw^nGq z*r@QOkI|8EVd#wg_s@OA<}`=k^H}0D+6Qv$o)3>y({Cr4#Cn@TkYF0G<-wv$doNFW zFCU1=EXfy`*~f!H?yAq$w^;)CXgDmjW+Sj^iLs)JK| z;nU*)zCFL-Pm|K(>g$6WGn9fP{%=Qe%SUR*VmBcum zyQAK6xaDyJlG8Edbj_dNMdh>fuNW=$LXk=1ZKP-nZtgp+_-m9>E3SdHd?xvycvDyg zrWN^39xnfKl}$}JhM!Whxi(sSOl{O1yOYkINlBIb_j3J2u+(V1Vh0O6E0w zCOtY{oqjGVAOD>q{PVk}Zw#5^8rYPBgO(%cwoC}SLJ1Q$HvrCTTKv`XVwIv|(1pHV zb9H~>&h6AcO!{3iCo7Uc3euusm+nV)v8${$GyNKfZU|(C%;Ac2CjH?yvF>iJ>l6>W zm9`r3wGWy;+iDFGs0Hh*zt$M3(o-jG68An_zRvk8wWZ^JSnlAdo%^Zm+TUf$%mh-nd%j{YS!`VYd+ zcY0o7#QJUy*}dt<2>urx{|dsPa19b^V#D?~0+)I;LT@+bV3Mx0;}KBB}u0DSC03m zud9#F;FXv2QbxK}e}8*tXtN%U`slxk|a!H}t@8N$VA;z8&V#mvOJeWR{!BQ<%W zyX$e`##n)TTB_XNT!Dw}WPfs|oTgXQTh{YV?~-@tfip5Cev@DPt`}!L4BoJ2_#1aY zC;CACV(cx`!Ga{V!-3oxJj^1c@__LW7HH3Z`?{>nuWaV0KIBSYgShI;YF+D%`&R?~ zZ-q&o`jhTLY6oKe?oaXHNZ6&()BAYe@*+(ZFQxHiC~3?{5K{4^V73{{}15b9n$-y<^;(8=N_p(!J0m1g6Y?S(R05;cStQ_zjCHOS^44932DZ@a>e0g(sE@= i>aAbt$Q^eE+G*9Ej8Y@w?8)EgFKtbrM)AF8ul^raG4sR# literal 0 HcmV?d00001 diff --git a/docs/guides/interactions/application-commands/slash-commands/images/settings1.png b/docs/guides/interactions/application-commands/slash-commands/images/settings1.png new file mode 100644 index 0000000000000000000000000000000000000000..0eb4d711ab044287eb2d5fe817128f05c4bcf89e GIT binary patch literal 76171 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 AQUCw| literal 0 HcmV?d00001 diff --git a/docs/guides/interactions/application-commands/slash-commands/images/settings2.png b/docs/guides/interactions/application-commands/slash-commands/images/settings2.png new file mode 100644 index 0000000000000000000000000000000000000000..5ced631349fe993587ad5cfb6edf8a1e35bd4c5a GIT binary patch literal 51089 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�`D43VsX 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�e0u`G;5A3a*;Gt1TkB~SBw@_XQeUQ+6$n9&f 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 Od8EY^#A-y0g8mQwMWa*z literal 0 HcmV?d00001 diff --git a/docs/guides/interactions/application-commands/slash-commands/images/slashcommand1.png b/docs/guides/interactions/application-commands/slash-commands/images/slashcommand1.png new file mode 100644 index 0000000000000000000000000000000000000000..0c4e0aec70b552b3323fc76d35b239c110069f24 GIT binary patch literal 10886 zcma*NWl$YW7^aQ8dvJGmC%C)2yF+kyIYb~RDRAf<+2$3KlAW-Gyq%-)8`0E3PaK0a2HX{Av#S86&#M>3c#zpbh+YL4sUMtso#6iR7ikwR}y^ejyv- zXup6$MkvEsM`(I!zDB}eW1wouam);w1oCj={%J%`|D#i*bAYPO#a5R7ucEAm*51LU z$h9c*pdyp+H75=)Gcxoy7SJpm*L&teprN7O=pO34VCCknf%A~lcIqeBP0r!E4YPmr zT?cG9If4XT)nE^dI7TFz96e$%Zbz&D%@{q@fEP-!^vZHT6*6( z#I-ox_n_o=w9jwg$n&WY!r37ZX+B2``Trg9SVw4x6wc08R#;qwbpiU-5(qu0 zAP>}N?|#JajPZbux6%I4dBQd2yawB^vx@5ML>AtZ2v4n}Qfp^T6}iz~7OJ2h&L}PF zqV*oF@HAc8nL!b`u{Of)Zi%(?wzu5#$e{F;jqk}{?3@Kq57zKXL+-#3_7L^&ZpUhf z5v1}wu~J&m`;A8RZZYxox-9=PBX6)i82dZ*Gu8vV&tySkeMaAYA8?zf5!U3LYzOk; zklf1`r)tf&Al=$fPp=UxI56ksik&nDwEuD$^{fAs1{%T6Z(-|KM-$d7))kF zy{|84k`f9l#Dy`~ndd7Eb6!m{!}ZGHC9KKLf(S|?kzFluFMt=vnEW#orD3rT!8g4G zCd!1NYf-Otcnc-45Dp~kW>bwQ8Jg>CK>+<&#*kBw9jM4C{A$@?SpG4>rODwV$=K|? z8O1fx=O(n3Ypi}XI*;ad3f3An=O16 z5S1I}Y8Ki78;|bXn;Z4c2&`)nCB;smrl%-Mq*zct1CZF*w!y&!JU3p0xAze~0XF$~>A!2Y zsqbl=WiuYAtj#2qM6k z;dN}uvPut0-{mXRGxH+mwpc+ws|?%=Y|VCC$#Fu&kX+B=`Xl*dx8u%(YbzKBr(YH= z`)0LpgkQOBdN^=I$gZP}t?|%YpCRU4O4JR}I5hPHx}F7PWMg`h$u1^HEA=~xJ8qiB z`gM{j$@q5P^i3%=mBJ3WY?jr8`}#MmPXn3v6A!fMxj-nDe&(Vc79|bWXwtwW4XvMI zaeLE*qJ!&_yBK6-QD*Rt2j%@_`U^)mBnY<0g`I5nnEAJtzX0B61JXdhw);cOJySUh zW0vXVg)K{uY2J}_V!-mBCTOmP9?_)CqykCFMH`r8lcc)5^MO4z1`qE$870b^B>qZ) zM?wD`>K|zQmh*p;wp$8?g9M(tJs>`w1DS@stVI_VN_SjGEuEbl7c1H1;>2$&C8$sN zqf0u6(8=vvTao)zC-F(z|J_W`!+-jv#y|i)%iVlhOiCf~BGju(*!L=3-)`6b7H@o&;$#kfb98WqG{{r7Rv)NUlE1$ByL9)nku$n620R*aZj6 zgvw=2xs^Nh&ePWKHNr@{KWt1%*s>eNO$QY^9No&#nKIW*0{1Ep>;; zLio}f=79}m89qb9YNlMlC3Q1Rk~QV%3wxgIR!o+hiAZQ%*Gqve**$V%-#A%F)Z0Y% z-UP`eQC|lu5>#(8?s^2tI6{ilMVqe=4)$m^)=xbiv_9dt%`S|bM_iSkY*Jy%aTsE@ zo#a2RZx;wiil-!RZ?#@c76>;bw}yWNdr2D{_f?K`YBBp3<14bk%>~ojbXS4Nj$_Ib zCNp`J&U#oQ5Wi$DywNx0Hl>VZ65v@p?9?4iUE_$nLA;yk*WFuE>i-HW`o|$*Qn-|B zUI5Gg61|mM&~SDOd1@*~R#%AX^D z`lNp#R_T0^?&+_z_PABf~XjfyY-2KFy$k zY1leVhG)r?Zagq1)^Qvo(Hvs#W00gZ3-fLO4h$AvocU!&@z-5JGhzX@}Avi#^- z*Es}ob19JE5kdLT5)XlNcGJCDh-yaG?;uTrDIhzdJpDsP~L;$s9 zaE{lZO^j{eB)fMih6>&A75QXhTk$a^SSp}@aFGDFddwy z&clm&E23St_6U-Gm<^k153|xbM8mr!6k>>VK8d0MSb2ypmHlDOPGZzA=yq@WF22A1 zGb*I35xX>#^?g}<@w?>Z#)izoPQ@1p7Arf1(Mz5C1&{$tQ^&p45UN<=AVKY&KEp zM9C3~q0KFl_GU>4lsoBb@^B+vUARh)X$*MMK71SoDdnWA9Rgd=Lj~0e-l2m`;W1g5 z=C$5vva>mEdWMGw4>`#He$n=$s|z`CP+H5RK=Ai;ON;-NatoW@gKLASaELaIggulK z9=TC;wp!l9Wv8mZ&slF0-IH`WPAhKC55CrF~f!vpeZiXb*?CfeACZOqD zYv*m4Kw{5wYB}^uguU>5N!zNgdwH81Hkxw&briEQhcW3sJKarKy(DW=_vsZG^i=7s z=t!chuq!86b53=8-h~l#oL=>@O@9X=|DHSo7F^y$haMhn9F~yyj!}JXI3e(03cfI= zlYq0$=qm@%)hQj3Y0rUF7f(F|)qj)5UIToMkEXS$2C#3!mp=yI;zy%q!C`jyJ;AWM zP!Do^h?`kf5q@({97lDFN877NF02`uujQzlK?8UVTlLaVFI_LiESrHtG6<<{P5r;$ ztD=G)yG6pOhvWWyr}HEq7}SL?Of4d`?S6+CEvV7|CxU~0Ku2}9=B3AR;XDXR0-dTh zgWW|*N{iI={!zK5^Ng>M*|+dhvt$Ecu@jHjOxg)Y1)SLQLzq``24`(wCSNe*x6TI^ z{oIv={me@&`ifI0%F_xCD^6b;3saTd<5vY{C^2aSxylw?K1&XAZZ=MDF`a5V)nFJUaO)qS6B!89?ON_e^PR^7Sl6bbo zYi3!%I?+D4+Hh66H4vgWx}vvA*e=}R( zIc$!5u|~q2)-}*_Y!-UN{6#S+%ZqGs_7;M(g|0Rxfgq;!g8g5l=Q|$x`z%sWqs6T7 zYhD!x_n5&EuoGL0(M;C?*ZZ}Fkk2(fS8!zV6*#&j*tpjNV*mTbdH-?3pd_$7drU4l z4T1*G6PB`$wQfu=hsLZ-o=!%w;>I*(=fPbe^o5esEsms7(e1}B-e$L7>JIxUR;YU% zK&TLKKn3YyOv65pm3=9lHV%2hcz~zHRSOsuFW%L?^4T2-$4DXDzfpeZ_CTx!8@b}T3%6}8gVBWR3tHK+Fp^&>&*Ojq2~&c zfR*?HDBsUIC6I5uPAnpDwZ^( zS4P|xH&)H4hMsaYef<{1$(9F@RvKRJ)=bGCvS>tUeuvD-wKn8LVv<`Hx#KYqQo!68XkX>6LUl}weo#N-L+ zQk`m&ZN4rlQBZ!O7R_g~cM5i6H^AsL3lJ2Jq1=`0#07XiCwljtx*)84e>czN#x zJ1+Ceb2Lu$$z`HSjA^fqaqYGCmSMb$sOgneEEsrG-)hR{I)ie?+_yoP}t$=f9+ zv&%wKP=?K_L6Nt2C`bRRwP5nKc%GCT$#ZOVdn>;o!b#f+;ESuuP4EbyjYn+}qMPJN z@VwnUO@aKyBJpqI{e3-7G1Ni}qw9KWRGDXWVQJCTTng|lR&k|48vk=VSDEt#o$7w# z>kbI`gTve5ps4AVRR1=MpwD&2H+yWTjnVr#ETs`4I&`=NLx&Jq+tHtd+Nc0Sz0X-P_4Qj_zn+ik?!^4W)q&Znh=79DAP{{8 zAhIRikoTHZp_^6cLL>2#5@l0&v`XTA*Rk<|Oatkpsm8R2fqSw|TYn%M97x7m3#{23 z1Y0UNJ+&LyS=?}QXVBqK)L-Z5b%EiqXL1q^s>hDS+;~2=3IOB?1@@V*ObM*$-Jetk zSMv>bJ1F7R%i--skD{{#w`d38-}cDz*ouXJ?FA3ALMu8EWMjts2OgFzW2v z;&g;@UcL0on3%0>NmIwSmhNz)neMeU&xxDwVe1$1s(Mr>fAA&b9EZN#%YmeSwqr_) zrSSSL2d31{FRiq{5q2gvB2U2=4@M8_7~-(v&pq8m8&x$mpX{TQGd}&z$Y@RDUPDoq z)AAeayRyr@SY(BqkBUGT%?A~Kd4(@4jc)m!V&@M+>EdyzPobH;Fg|KWW7DIK?BaX# zd>J;w>q~UsesUpynmuX6NKu3UVLV&N6m#oIfg+#L(c`MKrSuQaUAVQ9O@BAzOX1At z1&7t;HvhhH!`G*nf-TGZ%ca(?ATUkf`d`>{65@PCm9FTn_?BYPh~l6pVU%f=UkQi< z!qN{Sq10G~F)xztM@)g9%=WI-% zYw9q_y;2hv=1@vJ=r#Z{Qz!YhU&31>h`J|}RH&k=`$pi$5@&Y~`D?%YK{&Ard(JXL zRKZy|@bI_si%oM+_Gpt>GWmx@_>ltzY5Y*7p4oV3RjJUKC>AyztmGB8qs95xD-vI3=8Xs zY2{>4%*w< z$K~KJ1ZkKtDBbJPPYm_@BY1R4|7kT1Y{9X8ybopl49Bcw zb4U~I)uM5@upk*9zEM&8E^Ctf%0Hu)tCO!NC#02DIuDXplrA%+el<+b*J{-X?$3S_ znqT5$YS2G57~{D%fP%WbZPdH{p0?wVf~3QVFNdsIw>QVV=!TaZVid-TnV46SFZhMs zo#J)63y{7;cdVSa5+(4_??jv7nWe{DgVy zo+?7$ycw*Ig;#! zy~_qpg!`NIk2;6@#l5eH_fh@a#-@L8qC%JB6v zHJn5(OD>)Vh6AV_i~ZrKEHJQ%`ItC*)dWgUVgT^6+5^1AMt?60nSv2+btrBkWvB)I zj7;vLqmk-FOr#dbc_?VOx7R|yO7i?zAMxs~PRBWO{PQln4+r+Irt!9d#g|`fL_;8o zEDd??tyA&$pGsYbb8UMURNv@?`~$w)wVAWnwGWJ++6O2m5~8{?3M=O}w-rM+5tJ9| z^*F$Lko2?foUQnV3@Z|B>pL1A6__2;JqjDcZj}N#PP$eqW>>r^DZVX2Xfueh|w$VOWcJgfh0F)Yfsf{Zo{2*AM|YAaallzRs4jNX^j zS>1D1u4IQxmLTOHE}(d|>iH|HF$Q^gTvhN$gmkspsps!qmPxK(cYNp2(K8rXGUvnX zM&AOK^v&(qZ{jZp^e-uU3Y4m)X+|oJ8xm$#d(Mj5*Ozk$KBFLgo6%+%5;8kws6meNkO|)Hcx9p-Kd(t8{KPZzq{l{urFa5$6(x~0Ybms&`Dke= z)Aq-Yi-}8AenxfHjZVlcEvcW1eTlBqwCU}^`Mx@mk}|~1*r&u{{AT>iw$ZQ=@wary#IR@ve;#H>jdhW<%yFF3R*VBU1^v!#oD^+OXA@ zG>-y#;6x(yQ=}h{3cGBM=w^Ygc(hI7MkY1H{U-gdwGzxm83pNNvM5=vXq~fLLu1@c z=y?sG7w9O&OXcV|M6OB3_`T>CtHdg{t}7+IkXL>Unrhw*pCEIaLzU?|L@x^qgU)}- z1Yre@ag?Lr)KX>UAN_-12w{Q0@PEX}cry8|0)pD9NfSflzk;oqP#aYxsrP7fYX zi6SBFNjV#tRnt35vnWT^YhPAIh-R0cXNjgG??B0gOc&4n6H~u(EwPUW2fs_pAIV@P zl$ZiSoo$esFRFfReq%G+#f~nmg=pnhGzVo{{E^P$Z{$M7KmVhI^?>?6wZPxSeE+8k z_`m6v|Bu2U00bv9XW;tD*&?3<`TvWb|Bs#g?|SL~rAe=G&}4Q=34CQ$75I3Evb6>e zH~)ATb#LDkYyDH!e1KwMO*6ugl;|jIxRA7)8#cJD8c!tB<_`h$5vvGAU&njQ0Lc+{ z&i`6Sj7q!rhJr9~Fvy4 z?)#^R+Q@A~HUXv-u(=(v`P?#7ql?*Yat9YtMU4dqww6$v3-GUWL2x921Ai;*6Ulc( z2P-8;bJo^>%rD@t;P?{G%&61KpG?(?Zz0~)IZP4UVg&tVfI~#KHCxR|yd^@?Pa4+kH%blte&yd|J z-e1+xG{&URRmK=6Ud+B61ph$N^nx5g01L4p7)8xQJuD%? zv)^0I48pOT>tq6=Qy}E@5piZgVmTVzgirPNe%+h-y<6?}G+w+eIln%&=MD`tD`BH`HPEwVKdveA3VnW&}sA zE7@(pAb$0kR_owwIo2G~<*h`F_r&i;AIU=qzHKM8gk1P-jPN7dXv^E}_oJm2{BV&< zwcK9-i$4TYbzYKN`P1aAHV~Bhq!L2<1-C8!?pEfpapx#Z-lvYim;_&hh&hsFYhTCQ zs7~;4*0)D%`FCY3d__WdUXA?4b^J;Fu&RXb&cnTFdUjf{aL1VdT#R_`Gk32|wdk>f zwfU0lM*MlA2#qZCADv>E;;K1TSLd*5G;eVQNlFrgv(}GE@k0M&*lELDBXUdCScET29a8qq) zlKpcVf5i)=+=B^K_E*WD&-`Lf_ED^(p!oESnBdu9Vtfnl!nm#Ihjy1+A{u!deH5L{ zFaDyHkJF{-m#Y|(HG{A8*aeU_)*5z=83uV2>3rcHB&=M0j8=UVoJnrr#rt7|uhfXN zaQ7)o>PZ5j2QUQK5uEFT2L+T{B$g> zO|}Eu@h7F_Gmjm+j6y15-yzt5qQ13>Viv<_Uv1-{(s_)GgmzPES>5b5pe;?~B!JBd zS~^>uXIlr{;}J%35Co#QOvCJT&V@+>NH9qx(3qs>QT1f1l&Y0^pyAH=U{1qtq*#D_ z^p=Qvji{VO)}!?%RuF_}{!Qibwpc^|_F5o{aQA4jgRV-yUzvGpmuo$@1;yutkAlLN{MLJ#!F0 z6CoYXyFgm2zmeOlMPtxEeqH6v*XQiyGSEFBx4vVf2D}sSBUZ@xl6wwl1qLSA8W^+Y zF6e&0f1+E?WX%vS;n3sfL75uE`ng)I&0Ei*_Zo&T|8^~8=bun#C*A@m2}E^h_?t}(sRaZID+;;Bon=@*Olf3H?CMbBqZ7JeP(V{!pdm()v)X4g-ItkoN&?45QD!Ysnw zlNK0KvpEM>$$13ZX3)H(`naiV)H4VtGc7^b0x@PH`d*J?sSlM98C~@I%HOFM`wKGz zJ`*DCy^mhoPF_<#e~UeZLkAEOmtrTAJ8+!b{(ga6yL68|F6u2yW4Vhg&N6x-0VUZX z#`TgCKbApF#%XI_t?k2t#EUU^nnpd&Q_$O+9d#!Z)ynIFpuMgJDQ&7G(2{kOzbgZ6Pi ztH(h!N%R**{?0piBmB1s`KJ}K+N;8+Oip*K;!2@-ix`XqUz3W_6_l}x%q%PCab_8j zv>TfmnC6K`CkSjRA!HiH6F#pCLQG$0DTLL7Pem;4>CxAcaW=T?o2{~qDCuDK4#_-g zxLv4zBqtl&);42~khtFDK$5wRQz85H3>v-IJx%xg1e}BT*j&$7I7h@a!TFPQN6M_8 z^xw0`;xKQT(;8!@o@z$+u+yOwc1-^E2!Vq{XX(K2K~lG^C;WXG`YS^{CG%%U?%&zV zTuE)?74$qoL@Aszl7oxWL{mNiL(J}~X3cQv0#uokxXrXur1Cvf^^965ZLh_*+S0JfCiXWxl(JlV&L- zQ1D6O{Z5k}Ba+L3k63>hur892F>iWzq*VJolb7=!zcK!}$a?Qkpid8N2r#V*Oak>s zB8+6WSuosmXC^$J zZ7lp4dgZ{nSCe1sOVQ4F*C}|PuYfl%Mdk4>$BTaoWxz%~GlAwLd8b~PZ*bDwnkhHn zs@i(l@gN%cYN@yKqLBDHxesnB;HG<+@=7F?m6a843vH0DB;;j-bjBL36BEde7^G#N z`O?jyh^vekQU!!RtxBVxUg&zA*{tAd_{R9%2OQsrxgmI|+vm5^r%>i=g%d0~ zjsGzGVMP5;69Yzk9d+XVp4_?Gv?nQ{;qY&@vtesH@0llBr>e(cwX5MREWziAdbKfD zx(qesA8SY+b%?u+C0ob#r44T$)Szt3KhLJmPMi&l=$mFLJ7+q#!`T$~g1+12DXCz< z%)p$N|7Uu9#brM!{ltsGxBsix@c*QYDwmA{`~NJ8&vt*bbO1S@H7UzR4Tkh>u}`un zaE}xnJ3eN_Qv3`^)=4M87Na5awx6`24iqfhTrbzsGQo#wD3*~f_7dH(x< e?#$i~=p`7xo)FJK3>q+qOIE*fu)0ogG^pc5K^D$F^;Dho|5FIpbV>V|*8@R@EA_ z)~H%@Uex$K&x%r3l14_rLjVHuA)99~`>G|HdsRoSwx zv0j0R4TWI_gc5B*O%r+c>s)iV7Wz7wno@KSa~C7=7UDac&SXEy;bnK}IpICY#FhMf zABNx|07MLC7SkN{{@2-4kZVhD{`bsMbucV;aL+*hjg@;jx?x5!%kI=N=w6n3l7X=w;ZtJ8Z=`grKW}*A0Ic-YnG!#z>Asr z7oH;@L&qg_HhS+kO~N8NKQ}NmdF5VISO_79#!?n4>)offoUBJ z4?+eugheImR7-hyaHlcqhCe>KHnp_uCw~*_f4RcF*0 zkKnYzcr;}uI-;bAQxSW26M@@!nTNU#Sqx+)p~Q!u=T0Y+Q^?s-K!egktF>bnWS!6N z9Ysv1m-b(Wjbbvykniw#LI#ger>*X+Tv641hl1IK{^bTH0BE9tZEHnOPp_h{8#90Z zqiKT>?wg#bjDo;)%6FrSDsKiM)56dy?W2K+aHX6Dp2LJ0A%|R`J#AxwZDmCL zYcb9-0!M%4GRfm3kp!V9;cFTl6o+P?mKTKR_hFNqm;!zQc>P4$6psXgfjuWCYQ3@W zK==ezEOIFyAASM=tQ{A=>xfaY*>oW9CWL7n@Ha9@W;`SMFa?7ZfUj!C!fN_pGsV`q zxQYoOw6vjI`uUEO+e~@VUxX-en(3$Pxn+`}SrVRqxv`CrO-#VA>K| zNSX^uVN89(0Q~&)G_c=D#LkW(OQ*_d{i;bnY;4FgR1GJ`0jHTSdWC5^yM9lm<&TpO zOh9#sl(JEUe7vj9{+5nJC#SNiYqlI%wsA~JokA&*MhPqv8bf&6bLJUb{&pl9AqLUu zcd`}Zd`1N4t=28^h~0u&+(#c34^#yM%&evEvq$QOEdF}31|n)Yz9UpJ8zF~IUi@ux z%ek@TrM)q|b}U=$Bje?&%#1`d7!MapyiV^E$S1X9(~ss!7Vda^?)=6kgzBW_u`=V# z9*C7%#y$dGkcb+Y7+<`JCnp5f=Qyo${U#1(GoHpE}`NqdK zO-hV`>|?QDwwxG5DBAJx7%iyl(^U0HcEYynzH|X#kJX$`xC&NNJ#qru4jP&%Jrk7L zkJI@qT589I=Idll%6OM;sSXhwD6)^=I-N)4SOYX#`E2!P>g)L|2J0CJxrS_G6vAWX zvC0PftIUL?N7}X85|D!oO3!hL%z}qsU46&8>wn_I#`nm)aVYqBKf_+;XYR5|rKOyJq3#irZZ&vcg@Jnsg)m5@ICb+W2BS8y)m{h5yj#uoL*VJ7Ye5@wA2t(_N&CRVU10~^xq-0Jx^$eN5M3-RkzWG++NVpU0|?|mDdXs zeh;5NC6@U<@pd`4VVua%><{((36jB>?T#Qn1PTW9eYJK&R4>D%`07CEU%Syn3V{4d z`3t6dpKfLwUI4oOn1V`y(o2N5zE*)Z)XM1Hxzjz{xRN6a@%Y81>b zF*=|ydlLhtTO$Xf?Y3j1FdKt261>XqEYcDMIk0TdDo_1t2V6f%w6PLRiU_=~P0_~e zSv0W8iyu+p^)NZxxNs_?%M!UFLEeXZzf(qG#iKJeP|0-Y=t`06eGEip{+1R#;b^(& zV32bWtYKO-@Ts6oQikhqtVtwn)20qLQ8x?wH)nK6wxvIDp z3VT5s4--d|4KYwtnTe)EEZ|T@6E`-P0PN5rjF2gobJek@?wfK}nE>rD>BM2Vq2rPo z7Rp<=Dt(YTbjCu>u>Gl{wACgJ0=9FwipylFymdViO_6V?k{% zo(%uTpn#aC(TVBvTzD>QwrNk60v9tp5R7q}OorI+*|R6*=j_q8d1I5IxPrz;^y387 z#XRQWxk57a=GNUJdtG2YiinyT;%a2{s9%8yk_1?$#GC`?v{lFOUY~qFEn2M{NFIZw zWmTQX>U6PE=5%C4n?oxk!Rv{0EUskRH{h2AN&jqUw2QZdwB&dU5$Ja=oOv3Ymd$wp(gA2Bv?vw@Jw7_~@$7)Iw?4+qFq4MPnP4yJ35v)DQ%UVD&+x}%^%7hK zAMNqzkgVugqo0*xY$?@b%&<%H(Wpc!vVFtVRMyj|uszpf8HKTF8jeg(=h(gJk;UlX zJ_*=BdSY%$F40ia zC)Y9lI2pnDShz2sq?h~Vu8kfwc~}5&?C!#}Tx558@Y@+a5PpZb?)JxG5NiD^bG}4Q z;N`Iy#_V73q0K3Y+&K~nr69^7+2S#Q{6b?LpAD{=fLpLwMxTqll5L6X6d#D1HLVf) z^N+~;@8huvO<&B^m>b|pez@4iHVr`V70Uv5-~dSY4a30kr@*`MU^0ZZx?SElacW}> zRws|TN4wFo#&AQeGT|omG&Nr^`4J;|L{wfhgGTDd01)N>-7F$kX8F&R4e?8>*201s znC7Ka%^^0_JpXCjo;}H!VKM|AGc$_oHq#nG`N!CaY6 z+?RtpKR<~Do?}XHUvg8GE%hR5g*}lA*Q7dQBzn+v{qKbTczqpZdN>&<7~8c${NB$| z6H&uOLdH&>--TMv6Wxamka(}b2I~1sG|8ObFGsm(gcw)x1(kiDzU+iCzys&9vfyEDk${uW2SCF|F zKOTB#tmm?&=i}#-u#BX~jc={}!$Ke9#aN@;s^ojhOG^t64GlduF+rvh)0fq3JG7#n zDCiy}xh%{`tQ3ar?umMp*oA?sfRi~m>V!k9l+VIC*l2S_@{M+*ny3AQ^ZoPb;FLp} zJU1-2LcEd>Z+u}G$IobH1-zup-j#fefEvL5Y$6s|)7t0)zL;3|YZ_RcGTZnzK9Bo# z5uq);Uq_HDY*8Kd)05b^)I&wQic}Oa%@jnyRXQBL(J^>X;_5f+IF4ouWMn?JA_a_& z^C$ps%iQ+67LW4z1yo$ijGv~e6k)PQACURuFf2e`uHa61KK$TzZE0SqKX?v?hv2lq zT;S7<(lV+iXR6;2!o6@`QQ+BP7)VLM7fQcj%gX=6C$UgFt8O z*zvoUui#1sU(q8l(_P-dFS%!8ZqD>Ng;4Xm zS2pJbA9>%!$Mu6-(GVh=QucAV%D^f6Pb63byMaRF3fY5_dR-pV+%jFalSf0}M1_jH zxuu4=g~hKwMy}S@<$valxTeOc8b?N`cyg7TyGyi%q}Iq2yyyWIiL3#L#|2{ofRl~j zgcFjBRQ21k>2QkHno-;O?5SpwhMpfeFwv%{KlwL|PXnW0$q4CY5)5MOz7P-|SQB82 zg`YU(ijQUn3y%<0+C1ScBwLJjS&u=ZasGzy(Q#TeQvP`y;R2(}xLDK)sekV{p5$qolg($^Ix+-vip zz%S=|mQtaOi`_vR#7yZ}=d`Of!4AaRN6fSTLB)RfWt!(Q^^xsG%LenHV}=F!pzzq= zb(QhvDJ|A=YBPi9bi8FL)T#NnXj*oqf7(J3?eL)B3ZYXek^UHDG!ufGH6alJct*lR zmpSI?_vRH{DwQlndG-Xu_cmpESw0k)D@x#Xl_2tuVBj0aGcky{Y|Ai>7@=BH{4zDE zGoFg$8OPw#z>b;;eyWY>kIPM+DMG;zgm=pY?N|1!3gEhUJ7<_kILaSuFn9c3@P}M- z`Fd~8HA__W)s?8oDAh9jjj2w3w6DzgqH`Dv8~y$_hPk~$VsvD(m*v!VF%`*WaOGkV z4iRyX&|@>`{M;rbH8pBrc)OX$d;;V235FvvW6SkH@z29U02O_#AnFy6k+svsOx!4m znv`?MtYo;Iqpf`*HUOqMk|;uGReT!hgam~>p4bK|EP}jmJ9K1P=o{->fwWZ$ymu#N z^Rg%&c{ltVmEdM>NC|lfxGkYhgw@RYLE~Ibv$`uQ3KKtBgaO}b9kEYMjDr2Ryi?#b zHa;0TMulkWOGFeaI>KC|BN%n+UW*|>$|p8tuku^T;4-_%*j_BQ-k4ORXl?&IWlWvV zivtua?7{orhuJgN!i=!c&`5_D9T1lFnf3l;=)(NGQ(+m-R$Tp7(_IMM+6nMkXn6fE zcMO)q=~29!-iIt3ruJLHD4P#@gyh zZCk>Vq;KBj)qb}ZAi@P)Z)^n22fR+FB&CO&3K7@k)QIW%a>KL+D1;=4F-2&oIKG-< zaHk*hAIHJXfWOmuuj&u2*w_;-{SA6%N^h&%VXzaBh&86Zs7;Q+`A2h*5V6_*M}uts zPa2d3@BF;$^bZi7sP;4dUt<1$Via51C@rE)5j;2#G?NSM$3f2RN2;EN3sZfa3fpxX zI6Dm-T!zqpn`Y9irzS?KwrgN z2l)gOdyhwjVX;x^l>S5mra#V1h+kc9LyRxVMAd#9b7)+j6prla8M6RmWSY^@s2l5ASmSTelId;_?af0u7#-FA^^=LT4lQk+R3WZd3};M+6AL$9vVC(4&}=npEKN$|CUC zK)a3`n~IhILYnW0@9`oQCd(Ka#)c#*Oj^at=f_FYv1&(yTt*Ef{r)=e9SO)(*S%KU=5@W@ADscQoj7<06C!nan7Q*HpTm2PZ2Q_9DVg|*To=>u=&Uf4F-PO~$74Buh!gt<%9sA~fQ;g@GPecm!&La= zp`HA?c|&w~Ywxc#4(I^^gwkhi=f~8U?nvaA-y!KYR|7K!&IP3EA-XrSa_rX7;D7F5 zki{*9neWL9IeNQY@A!Nc3iM zsW1yC0fcjESd*maD3jT#L8(VB@lH5Aw-^}6z5wS-WoaW6##xcE&dypC@%i7Vg{OSv zwu;WdD|chJg;uSEK6KDHV#QSE2W*^T*;{|MYA;t+n1A`k%pu)}!E@^lPl;6E|AdDJRo!8@y=aVFVqcIl9Z2)2 z4p?8IadQ}%NN_Priu6PO6{)~$W@0>ej|UQa4=hgncGIr$@bCQMF$dpPQ$EMS~2Rc?X6b%Ft9qgFP^!9`Arp=_BJXDlZb2zU4Bc zmTl0!bCEbg=dY-=8NP5tK5KiDqgI6$_9!4+{5;NK27912H08kfEe+m^Q4M>5*T8oT zb?;aZ&L4lD--LJ68G6JiSnAkjg2!^;0O!&RMw&iB&_BlQYIca2JJtJ4r@05xz5!P36OJB@uUvTF?YR`qOnnuwSL^yH2kX` ze~d)KN2Am#zAXf|MPViyhRTqrzN}Hf&$YvYJ#b%1)kayEx8Bbpi3e8L7Q%(y4*aq`y844*aX(9@bGq*| z6p0IN{PhP-1aJttCE-2OQTDFw07=`yog+hWQ@QcMrckHQ2$UuXk%jMZR1FZ)5r8yW zS-6&!!WMgoUUedjkn(a;C$1J09+7+wDx=pbyW$aPQZfNF6=(QJMD$s`op3}s>qt=z z2Y@O%xiMEbDIF;gUWL?2`(kdKtTGt*?d2o32}(jTl$?x@=+4;~RmWz|U(^IVGAj?1 zB7^=Peu;?|_Z1@;XwJ2=J4<6~oyC}%R*;Y=gJ9&W#!eGvAZ%nuLnXSDQo8~>A|w@; z^N{+~1fu0J)haT8^99lMMLtdb*6Ln`YLpE@om4lQ?lg>Zh6WNynxu<>5IHA4p`;CQ zh(wV+y_qU#q8>D)%MI2hj@H=!^x_1Vd8ogG&x?wc-EGBehMTRe!+gVs%X>NNRU;sKg{SQ(*Br$Nt7Mb(e!zD<@W&%}S=h_3`=j~zY>B~F+!yT8q+!^-W36~U65MhiG^c3&-wov+vAwTNMK_7PIdW&e zUmOc%(Z1H7Pn0x#w5u|pB3TEvrbVOQ^2KSz5Ya0=fFog=ZTgfI>vPqJ!+}nt5)4O< z3@nw}=+88V;QN~tBKZgAl;en-M9d8r)wdsk_x>@+S3pkP0^hSqNS+#HNP=@iZ2o+s zG;;!Ne4)ZJ;7mSNy#wshUTeYXv*1JkI)*!12rmWGU~|gAhB5&aqJ*fMW*>ucM|lpW zG7&-F)z70;$^8xIocpBshtw}=EHci?yG5@tJS84j=?t+^*Jn3AOLdf5<*l6SLN*lx z*~VfxgoZW?mC-QXKV8o_+A+c<57a*mUwA8Sn8oW2-6OL+(4ok+qhL?@JVW*!em%Nl zsF`Mf-3T<0y@{B#WbujUy9#zaXbG2Q15F-wmulU1r(rv8r)2YYsRWnlyXsVhMT$!E zR0GIpaz0m2lkgAEGd$I8teSOn79qJJd{-Q`;_#jj2i|d5 z2q{w)3Fyq;0D3S!Pw+Wqbpy1zo7*)o93BhRGf;7)L_c$WRfDG@b9wru-dst`yAN4CKMEhdvT@g?5u> z)%Ff`0H$vE% z_3M@eSDbmr$;^{UZ=ajKy3x(EF;_f~gQw&AnNi)JF!x<*w~ysEf<4@;0@qy#D}h{Y zL|9Wlr8g{1pWpQ;p4%~h%jhacLc2U9CMU$=B4n$|F7^8_d_`nNWoe22fCN$7sNniWnAB>DEQ))` z=sCD{Bf~S^dflUD=kSy5BZpS=meDsq z5NQgDY%E)|y@B20m{qY=Rmte*!yCS0`zYGhrv7#gbsQfo?Cg2_>O|?wKKbEs@U*rV znQokTRc2nSl|u?xTj3{r`Y$}8o19h1Z8G7Nhz%42TH@c9SH7p*==&pT-;w>&JG)6x zE((xvc(kWbD24rTdwV1ap|)Hbm)pc_%dGGbfhHX{z!dXjSk3cW&LDATF~?(<1nm zkPMAL6%_S=E0yNH#(CqsNAyUKLyM(lIDb$&)u&JEVQ|858(@YVxeScy zx$QoA*s2)bkg#fy%#OKk%CkZjQ=OvPAdp;$21V=O3kfbkhXuDR2-3i*>in1V9F^V1 zsY8{JyC6J&uHx1g9_??7V~t+KT(ur=3q}u4=>RmWdPRqj{l2)M^k|?CE})@lbw~7K zI30U9xwaR6SQhJ%wtL5@rCAR zOg9!1ot^J=WNAGZ9kH^($jBH|71zbCz*;5+p8qhQRLUaDFyts{nUwHW;m^bzHbEOrlwxwifSYx&a z5h9cvI8ask1mTagL3KL%e@>QdY=pbUWZ=Ui9EQ&6&IwiZQsw$KH(AQ8N;dXJE^bx| z)d=3rb=Pi9Z!*oy&CQQv695*9v(OjZo20DB!JdQ*?uIx1>IvVK?^8I4A67+Z-U2`0Y}T+r$;S zaJmpdxuL_O`^W^eVuZ~du*&ZXiTKe(8xni2y2f^WWGijDGy6y>==415;~VhIZtSLZ zZ-E?rt08v+(gg9BK{sETusx*0NL$#{{?ESw0`K#6SC4IE0H3JkKw^`-Og9m+0WSXV zGL|s#J6^OIbk? z5E@exBm7Z`z<5PBHO@uOpcT`B1*?>vXfCBWw^@=peNU=P zL`f{;;&Yxjbp^sa|FhT_o{f;g+2>pCg}jjKJdln}$zxxDaY!y0FA?^+{6d_x82OMW zIHZQle7lYZO?yFscsUfK{CQECL@w>z%l#WJqO3W;_ZKcIlM~Q%n%vas7#FtqWO(!R zC2-VyR1uj5A{ceoBQIqNiEOf}F1}s?Z=@(Gm*Bq#=5zWIa(#86IGfl<_slj55%)KYK zs-&LG4aU1_wT5od9fp*T3w+O&@kOgtiJI_+1nU&;Y%R5WIIp|k-`Ds#8GAvsNlSn| zmWcrThS*91eami5jdLv1Mk0M7gxh0j@aS2YStjW31KC~)IkV7Cl(^&~o_BXra)cIc z()VK&A8S_nw-PCtUi@w5_ktO+L*`U2)o&rGax%TzuIAW3dQtY4-^y7NBfM)cCb&e$ zj~ffq20Ab4MHo11a8bnDqVa?}yf7CpZVD1PH_g5?dLfCy5UTAt?shu>Lq8)hdZh5A z^q!H?WNc{2mqjv|JL_AK?wG~^%ll|^h$VdTxFHYIb6ZJo@9Jn;d_?s*cB@x(&sLDB zq&5U$kEa{T3C(m0<}+1WlB2RmzdwMXUW?udp7hVj&E)s27>ZTGgp5LIvub(fX0o!t z5h+18wz3zxsXx&i*zG|zy|%PpNF6Xf4pC~#1dIi}uG<=4suh|V)a<95n=&Vkthv3c zUF^$anq^ zJcW{@;lry@n61>2fUeJ`dA~z|ytIxLwT&%IQa!Nvz+BuB2CDuClGE#BqV|{)yqNSj zt@=i4!-;8aL{Xjuld$mjAI~h*q~yy`-Cc_1MW%73(I$9sGG=wN1+_`_&KsqR1!RH#N=3uMzUDX&F>Axg(#k0{t%bdC!sQX zWd2A^`;;;79jf~a`z%M#A;VEUKEMYNlN{g=Dg!?k^o|u26TZ$RbfYdCee>o)~!MCj-EpNf?sn{78=YX zLmD?!w~OVenH*TW0Ge~cnb_(X@dL~GD&{jap;}q{r-A&jGP-`qHjD@s6qXt#Ph|vn z(a8g=SXfGl3%P$yh`Zo{$MQ*I$jHq`zTJLwx~bNE=1Ad>OYWO|nmDIOp9V$ensz9S zvW$-Qz`9eiTp#6+JU-Ub!PU2G)s>+lo>-7isRWx&U8J5e@CUhQFz&lxn;7>C6yu*O zU*mUE+AX$QX$%=1i>-TzGVN;}Z0?AbH^V$#>YUn%nAWyR5{D~}%3W}EtH+(Gd_WC@ zAx1IF!iX(ckpJ}Jdc|@lM%zDtG}CVQNC`&k_`@)j_su$LnrJQZS!3_?48~b~2^AQj zY_q+1?0WcG%E{dwKe{)T5RTY=y$y(L?18Cvg?C?8|Epc~ z$cz1RN=4SEb_+=)Rzt%kLf2nWLZvjf-A~ zf;f*O8N!e5v5UKhTS2yG zr1bfNP{ZtvnCNjRZOLw>1^>E}&Xn7Z49#YO#Rw9G%w$CIVIqtrl$5sky?N3y0=b51 zm@OfMj5b!tvB@~EzJn~i$o=W?$#0vWv~mT+kjcN;2`?`~xdI5pca@}nqpqX`?*K`U3qEia9v zCP;H+rYP8rtyA&blP9nT6%dHDy=aczhTzGxV8&F80OE_G`gwOx0R?GHIMxcMQMW`V z{v4}j??l!msM0~n;1a2HLeG06>bhm>?UW?L~XVe-0*YwG^cI^N3 zpq{8!ndfQy+OXj6M<&t=b&AYekcejvJYI9nGJnvzwXpd!qibZ( zH@xmTsIUwp8ql%7mOwRl6mUjKSnKb$dhA|?ipQ$B8|@IR2nim$WLMPbB%^&xKYBT2GvfPh_H4mvhSr|a2Y zQ0To45~do@I~T3_39#B3WQ(PZYO`!KS!2SEdi&xKbC<#3KSTQ#UCwqNnvj=_nJghlNgS{S?n@-oETYw zaoYxc$-f%;?VBqZ&1^`DnYGF8SUr_qHw#8$0p9yTwa&QYlB54rge%g=5$Hc3_fIzo z(uH%WdxL{Ll0v@{DvB z1p7Hz{{S0al)=aY&VR0Sb}!U0yDqp{F!oaDewq#_NK8&8^<};xg_PT8CNoeN-glW; z#9}w-EM0vb?*??6hFuLNjsdh^gNf|+o}a|#p3Z8VSvtjzX;COrh(x^Ih}i$F*7p;2 zBcPvuo!bXlK|KWqcU+1_Hh}=5v7ySTZH@$TIIO0ox>oNpD_nyi zoP!@o|MT0sMv5KRAwPn05(f>C1>9^%*i<28n`G2wI=8nB;Nv$K;jup|l|4yltn~{* zRZ&sqhn!~@QIpmc4WDV4 zPUZ0YyHi<;T$`T5BG+2Ixg+^>qvH-7-WtF2;bMw^WKt3Hr0st@_}j%&p{dR~DesFY z7^Ue{hZdCx9$8-o#4eGR6Jz1PvxZA#ywtp@%WtA)|5{~k>24f^mTpC)p0u;FanEm> zkLutmJ)A92PE3g6kIP{H`3ddzj`^Jc2x(F}EtTYt{Y;b^0yBsj(sYPwrEgCos6V)^ zGnV-nyZ`PYgdSO2cJECPDQiFliyWJ8v>k3hA$?l+BN2D#1%9WBfjRotUCgxmu7Vf;w5CVVX%}SaWbUa`-A&xz;+awt z^41Btm{0h0myDUhxU>P-yG2uvf>~FX8)8DcKW;=suRFwhlMl$Ny^S*Oc@!rz3Kfw8{g{ut-%po7|VQogeQ=~+FpF{X~V>M)P>S+9)B6CzH$0zZZO_=LbO8>lak7Zx2Girg}vBj{U#|u}=Mm5w&}O&FH5oV3E^HhC;td zI9ocIoq$qb-5sBBu&wdptFA~cq`0KjWQ)Y`<+s-^%v4m}{sOn5WC+0sE~(4SpxTUZ zR0LMs-H;)L%kuOfh9o?f-v`m==hBV|HKJZSD&ntSg+^=lDy~K07SoVlA?bPksL<&r zEW9~00)+{zSvG*l-q*rH9G8aJKl{k=V-rZg7b9Yd(`)y>i&SAn5pJ5sHUsZ!j9$Nb z4Cd~+z}$!qWsOp?R$WQ4VIq@dWe(1$!U{{{9b|0i*nxj%;wQ_x215a^uDka)8cfyt zXZ*_5m7lLk9YA~wU89dfP640t=v!?m^gxmB@S503ac>^|nI}rm!JSqA1KIc8yPpSh z)LbvIhz&9vhO~VSn&PBm4i9#nZL`83SX8<~XXnVzVXuyaMCF(1krkSE``a*3 zW(F~^*b~NNFjX6MaP>7NT_2_L8N!yq^#!l4@D+c}a3k2Q|D}5srL_?;e0Oyl#V)C? zc=*ieAk~4vN z97#HqfAuKlSRz0Z#A2po{K-Y)ZA^O4UgYF(LAt1tVf@5>_e5z-^ELDBZu1WDL=}lO ztnG*%-+6;`vffu)NR@+;MrZ}2m6g_aaNSp;GukOmsT5`5UH9(E z$6+L^GA-XpgF>$~MtSXP;fi8+L32CW$Dvm=w$=Aq9Y>Io=R0M2k3JE@?_rvv z9wp{AEtiw;GNY_H)v!M_9EU2-qGY1jA@Wd%lqRLBx_*z2O^9cl7;j-aj^?iDhaDkW zk`7k|vvOjtNB1Ag6gMbjC&j|$B1%nS9L|~t6o;B`x8@+Z=V?&46qI#|GcDjzxLprB z-(_dI0+zQx{M>pmOOwT~k!&5xves)yO%2IOK>3JrmSLlHg$b+Ghx3T9`g)g~valxw zTD%Wt3UQ>g%}4W1asya-7G}k;w0(c)p@$@JLLc$<>9nruRas$&>axhC+^GD+{J zYCQGDc2;smRNM5VHs~@H)$K6N*2TgC(T2KLb~cpPPcbgOX`;V~1Y6bj>m`Lmu$}w$ zzIO}?h;$<@MQ5J3*_A-uPULUzdoqSVGNdq+{gs_|7+i4o#nkixtd#IB%E@~7G$Kj< z=w1BriJm*r&9u_dwbqv+RRFqnJ$QUobi`A0F3!8q)X3J?gZL(wASxpzwNniz>RF72 z@rT~T0VHoc7Ur+o5|}i+8J8Pb2nD+EPU3bH`l%Anho$X?!_5zu_d`T&I6I*b(-U3P z42?)m3YphJ6z49>Q$|dDq5uLzog}#KZlV(#JvjM{=)dwcl6kL+U4{}W4UT=>j=7+~ zB#*k*nTV3~-MpJB2{HcRqL2v#XUKcBU?9O%_$CJ&M<(#Hd|;c5wlSwOKkx)2)E^QTzwT701e?Nx!%%3ShJFIMB(DqdyfTmgc#ssXqL zQ?&GOCoIXd4L-u%EORgD;@7!xE%WeSCh~a~g!&&(45!~-mr^|q*ibQg2n>4|iGjh$ z?zJ$#4l`-=QjoqsHhZ4RhefKo_FdnFjTXh-C)OxxFv}<6B!ubqbRpo{;CBd!7%9Nq zW1EvIq{lP+UFn#q2)grj3+}y&yCT2wakPHm1oU)*IeXIr_-~BI8>NP zs{1Y6^Yvst&dCI|MIv;e~=qr(Re|`$OzfR=& z5cl+wV*b7n3UU-|M3#;t>c6fYW|=k&TWS=q3)o;)sd6Fu!*rcVx;y3)zdI*&<>C z^VKDgRU_}lUPfI0>wc=}e(H=7W#3`Al{h0lVS)Joe&3fx!~NisSSaR25@;%Or2dC982+JF)ZYdVi^|*S@rZbrf2K>EY@}r~ zkpD(e>L45CV9v5tWt)Ha_0P++xEW}DoGkgiUa=GJFKNl2i^1N37~)ukp;foX5b1RC z1`9<0*Xq){8^4G;4{X8>e91cc>Q%3nXvu*NVu9e)V|LFYpZL8s`v@ni9i^`BZcJMF z@%3@Qc{TlAS25YRR#<@WliK_7O;s1MQ3O9>rG=%jx0xW<*D6@pj^XFsJF;c|qZXF}l#-JMJ%9x@vI4$4x}Jwsm({6#hYfhYYtFGK z)m;p?iJ_p-g6XgCuAl9a&+P@4aZ}P>cL9Bycetg~Yj+6RCQ9k}&h>n4GDX{Ky78Ky zYGEG{>&70c9%&qs-dwTWy&+f)hrW|zx9FuRkr^uo654n8k3NNU#wU%sPEs<%6Jm&X z!d{rnsd}EV;ZN-{3mp4>hT9?E0j8_&A3)+fH!}C*<_x9?P_CC&rg_lSAFM7_GFVnQ zgAwVYl+h;h?l@Y?+WnV}38SoDAWGG0q))n3zW3W?lcD1pV%k(-NfD0YSM@g&Pv-#M zoW;f-IRyq3d3Lg0zIN!|?WGq|$PH@U+h=$$a{?NzBoLfNUJq;pwlLEJJqoIi8&MJl z>rW~${#w0()npEz|;t2?QOr45uwSf%=?jxhlF4D zL)*f31KPYYg;0)aqtc;6Ov2woM&b=e_&@ipHo`33^GZ4+5<>^|!t61ljKciT<^{9(}^KwEs6?DT#79tV07luKsl*9-VUZi!{wmtloa41^u#xaWrU$ z_@!0QCj-+OoXE(ySVplx&D;!jU*)Iz%Oc1B=RrWITvGyq)3n^LpupG3@eI?Tl+pcpw zwXE?EulGr^H0ps`fxaXPIzxHnXQfb6DQS3Zi4XSm*y^86{cK;N0$-cxe}-E#P*o^F z3B_xZ^*_vaN<^^og01*kz-!5ce-r^lSH3@;tt0+(g#|FeheFr09|qDxi^FJaf1vu` z4<&n^g<;>erfV8ch$u!yj9<(uoc@1bDfab#t1Oj}rr0)CaC<5b({wO$9yQOQpi_6v%aJ!FL(uB$E}~R zoSFR7Xmt4>_;55qAC#FGtTCuq$eMHpMkl0x9&$T>)fx^@KQLujFpP%ZC_{c^ztt7T zM{%+Ee7%5g_T1$OO%~OT;WMYvjjQ7Q0rU#sAlwWl&j|2BL$R_OZXx_B^hRlLUp(7;xH)xqUGA-PchWA<1>uO@~JpWkS5p2yI zn`P7l&9Una55{>ZAQ1cO{yuE-m%g9l_2!$?%)1E26kcMYqL}=IkN4kUl4`t)J~!85m5iinsa0y9}e^_$Q=gzU-fGmBM}K zGxj6X=tukAEXP<9LSOascqcAX2_Mb-kO3mP3%Fia_onuIpk(!5^qGYVigng#tQRAn z|4%Jv7R&|$$KftEn5eTVj#90tx|Jwhx4Ns^x}q9!wX_(iG|D2*B7)E;wMbp1cI!w_ zEFz8~NLsCysWXdg-9!jEY?+;X*qMFY_y2q||JQHk`=#>7p(edT-kze-{i=faEQqMo z<{Eh{#}JYPX5OhDP~}%Yt)Y-W<1tAJd7b!@jjs#>dC=jaXm94S6HJ~3+3U2;*gZ`_3wOwkZ= zILUgVK<${iPoyQw5Qy+(wEoY>i5KOE4GLs$+ghN(XWM+ffXEAf4@ z!`t3XRRxd<9DQncGah5AxTMTGwU7p(ca}7=vUx?Xp{gKv;#{lP2cJ$O=5@2p5(k9K z9^!5EQR8-$SbhG3m_I*+8NiI2#*kKu9Xmp3cIT#Y#>13IwA7Ck;FzTWodP{1bUf`e zLG1ZXoVydNrru=a7WrXDM=Gk=91}1Qft#sQnZQ1xx49nmn}`Q_A(fT6-|UY)?uDAi z@`F>g)ogn8z=ejsAzeBlmfTRa|L*iAOI3M#F>W0TH_sHf%S&i$u2QmD)a0_KVx#1t zC(Kgf7{9z{58MiG4P3yfVJ%Lfi{Yj!UGAhxB*Y%uy2G`MA@AbKGMTiNKv1+0O!{SQ z+`^EqaQNlro{rjvcqy4WvKEP}Gi9QZ36?O!klMKd{Ov8UVO}%AO8^%emV8FtSsE5QJaQo7p|HN*?JqUXGb> z^vB&Jrbl;&3sU(Er?y#_yx3Pf9w=={aeWdMg?A2c<8FH@5o_s%4o@CYxD&LyYacRmNZE8Y!_P$Bp%Spu-mQV`^#}h{$Ux@^106=9KBBg? zE<`e3_vbfCY_L1@WlUI@duYre$ub#E^2zN?;mn}g4b7FcHu3pv9|w_!E~(X!~Dmc32@=@jj7k-F!rq|c@6c4qfvFG=M$S&7SM5rIAl z^9~wX=ma`!`Frw`VOR%xowq9@?qYq3;wgd~z}o@>w`@M&V2b`qi?H=|nGPvCu)*E( znFhdOTvE9sl+MU6pWp64G-u?C%5#n@#O+49&v&>mVFrhS_f|`&Dl-Ff9Raa9M`x;`r|E^AS&|~-mEm}&{Z?HKSCsCqaG;DR!K0qNF z^#9$z{L{7|RR1`*txgBZAI_gZz6a-r-^?CTN}Z1WS3>hYAk+Zt{U3}4Pdt#$Vrzfj Pm^tEPcllz2jep8tI8wuE literal 0 HcmV?d00001 diff --git a/docs/guides/interactions/intro.md b/docs/guides/interactions/intro.md new file mode 100644 index 000000000..62b2dfdb5 --- /dev/null +++ b/docs/guides/interactions/intro.md @@ -0,0 +1,10 @@ +--- +uid: Guides.Interactions.Intro +title: Introduction to Interactions +--- + +# Interactions + +Placeholder text does the brrr. + +Links to different sections of guides: msg comp / slash commands. diff --git a/docs/guides/interactions/message-components/01-getting-started.md b/docs/guides/interactions/message-components/01-getting-started.md new file mode 100644 index 000000000..cd5eadd0a --- /dev/null +++ b/docs/guides/interactions/message-components/01-getting-started.md @@ -0,0 +1,66 @@ +--- +uid: Guides.MessageComponents.GettingStarted +title: Getting Started with Components +--- + +# Message Components + +Message components are a framework for adding interactive elements to a message your app or bot sends. They're accessible, customizable, and easy to use. + +## What is a Component + +Components are a new parameter you can use when sending messages with your bot. There are currently 2 different types of components you can use: Buttons and Select Menus. + +## Creating components + +Lets create a simple component that has a button. First thing we need is a way to trigger the message, this can be done via commands or simply a ready event. Lets make a command that triggers our button message. + +```cs +[Command("spawner")] +public async Task Spawn() +{ + // Reply with some components +} +``` + +We now have our command, but we need to actually send the buttons with the command. To do that, lets look at the `ComponentBuilder` class: + +| Name | Description | +| ---------------- | --------------------------------------------------------------------------- | +| `FromMessage` | Creates a new builder from a message. | +| `FromComponents` | Creates a new builder from the provided list of components. | +| `WithSelectMenu` | Adds a `SelectMenuBuilder` to the `ComponentBuilder` at the specific row. | +| `WithButton` | Adds a `ButtonBuilder` to the `ComponentBuilder` at the specific row. | +| `Build` | Builds this builder into a `MessageComponent` used to send your components. | + +We see that we can use the `WithButton` function so lets do that. looking at its parameters it takes: + +- `label` - The display text of the button. +- `customId` - The custom id of the button, this is whats sent by discord when your button is clicked. +- `style` - The discord defined style of the button. +- `emote` - An emote to be displayed with the button. +- `url` - The url of the button if its a link button. +- `disabled` - Whether or not the button is disabled. +- `row` - The row the button will occupy. + +Since were just making a busic button, we dont have to specify anything else besides the label and custom id. + +```cs +var builder = new ComponentBuilder() + .WithButton("label", "custom-id"); +``` + +Lets add this to our command: + +```cs +[Command("spawner")] +public async Task Spawn() +{ + var builder = new ComponentBuilder() + .WithButton("label", "custom-id"); + + await ReplyAsync("Here is a button!", components: builder.Build()); +} +``` + +![](images\image1.png) diff --git a/docs/guides/interactions/message-components/02-responding-to-buttons.md b/docs/guides/interactions/message-components/02-responding-to-buttons.md new file mode 100644 index 000000000..00d651f6b --- /dev/null +++ b/docs/guides/interactions/message-components/02-responding-to-buttons.md @@ -0,0 +1,37 @@ +--- +uid: Guides.MessageComponents.Responding +title: Responding to Components +--- + +# Responding to button clicks + +Responding to buttons is pretty simple, there are a couple ways of doing it and we can cover both. + +### Method 1: Hooking the InteractionCreated Event + +We can hook the `ButtonExecuted` event for button type interactions: + +```cs +client.ButtonExecuted += MyButtonHandler; +``` + +Now, lets write our handler. + +```cs +public async Task MyButtonHandler(SocketMessageComponent component) +{ + // We can now check for our custom id + switch(component.Data.CustomId) + { + // Since we set our buttons custom id as 'custom-id', we can check for it like this: + case "custom-id": + // Lets respond by sending a message saying they clicked the button + await component.RespondAsync($"{component.User.Mention} has clicked the button!"); + break; + } +} +``` + +Running it and clicking the button: + +![](Images/image2.png) \ No newline at end of file diff --git a/docs/guides/interactions/message-components/03-buttons-in-depth.md b/docs/guides/interactions/message-components/03-buttons-in-depth.md new file mode 100644 index 000000000..f9fd67515 --- /dev/null +++ b/docs/guides/interactions/message-components/03-buttons-in-depth.md @@ -0,0 +1,45 @@ +--- +uid: Guides.MessageComponents.Buttons +title: Buttons in Depth +--- + +# Buttons in depth + +There are many changes you can make to buttons, lets take a look at the parameters in the `WithButton` function" +| Name | Type | Description | +|----------|---------------|----------------------------------------------------------------| +| label | `string` | The label text for the button. | +| customId | `string` | The custom id of the button. | +| style | `ButtonStyle` | The style of the button. | +| emote | `IEmote` | A IEmote to be used with this button. | +| url | `string` | A URL to be used only if the `ButtonStyle` is a Link. | +| disabled | `bool` | Whether or not the button is disabled. | +| row | `int` | The row to place the button if it has enough room, otherwise 0 | + +### Label + +This is the front facing text that the user sees. The maximum length is 80 characters. + +### CustomId + +This is the property sent to you by discord when a button is clicked. It is not required for link buttons as they do not emit an event. The maximum length is 100 characters. + +### Style + +Styling your buttons are important for indicating different actions: + +![](Images/image3.png) + +You can do this by using the `ButtonStyle` which has all the styles defined. + +### Emote + +You can specify an `IEmote` when creating buttons to add them to your button. They have the same restrictions as putting guild based emotes in messages. + +### Url + +If you use the link style with your button you can specify a url. When this button is clicked the user is taken to that url. + +### Disabled + +You can specify if your button is disabled, meaning users won't be able to click on it. diff --git a/docs/guides/interactions/message-components/04-select-menus.md b/docs/guides/interactions/message-components/04-select-menus.md new file mode 100644 index 000000000..5181ddf34 --- /dev/null +++ b/docs/guides/interactions/message-components/04-select-menus.md @@ -0,0 +1,76 @@ +--- +uid: Guides.MessageComponents.SelectMenus +title: Select Menus +--- + +# Select menus + +Select menus allow users to select from a range of options, this can be quite useful with configuration commands etc. + +## Creating a select menu + +We can use a `SelectMenuBuilder` to create our menu. + +```cs +var menuBuilder = new SelectMenuBuilder() + .WithPlaceholder("Select an option") + .WithCustomId("menu-1") + .WithMinValues(1) + .WithMaxValues(1) + .AddOption("Option A", "opt-a", "Option B is lying!") + .AddOption("Option B", "opt-b", "Option A is telling the truth!"); + +var builder = new ComponentBuilder() + .WithSelectMenu(menuBuilder); +``` + +Lets add this to a command: + +```cs +[Command("spawner")] +public async Task Spawn() +{ + var menuBuilder = new SelectMenuBuilder() + .WithPlaceholder("Select an option") + .WithCustomId("menu-1") + .WithMinValues(1) + .WithMaxValues(1) + .AddOption("Option A", "opt-a", "Option B is lying!") + .AddOption("Option B", "opt-b", "Option A is telling the truth!"); + + var builder = new ComponentBuilder() + .WithSelectMenu(menuBuilder); + + await ReplyAsync("Whos really lying?", components: builder.Build()); +} +``` + +Running this produces this result: + +![](Images/image4.png) + +And opening the menu we see: + +![](Images/image5.png) + +Lets handle the selection of an option, We can hook the `SelectMenuExecuted` event to handle our select menu: + +```cs +client.SelectMenuExecuted += MyMenuHandler; +``` + +The `SelectMenuExecuted` also supplies a `SocketMessageComponent` argument, we can confirm that its a select menu by checking the `ComponentType` inside of the data field if we need, but the library will do that for us and only execute our handler if its a select menu. + +The values that the user has selected will be inside of the `Values` collection in the Data field. we can list all of them back to the user for this example. + +```cs +public async Task MyMenuHandler(SocketMessageComponent arg) +{ + var text = string.Join(", ", arg.Data.Values); + await arg.RespondAsync($"You have selected {text}"); +} +``` + +Running this produces this result: + +![](Images/image6.png) diff --git a/docs/guides/interactions/message-components/05-advanced.md b/docs/guides/interactions/message-components/05-advanced.md new file mode 100644 index 000000000..49b3f31a6 --- /dev/null +++ b/docs/guides/interactions/message-components/05-advanced.md @@ -0,0 +1,87 @@ +--- +uid: Guides.MessageComponents.Advanced +title: Advanced Concepts +--- + +# Advanced + +Lets say you have some components on an ephemeral slash command, and you want to modify the message that the button is on. The issue with this is that ephemeral messages are not stored and can not be get via rest or other means. + +Luckily, Discord thought of this and introduced a way to modify them with interactions. + +### Using the UpdateAsync method + +Components come with an `UpdateAsync` method that can update the message that the component was on. You can use it like a `ModifyAsync` method. + +Lets use it with a command, we first create our command, in this example im just going to use a message command: + +```cs +var command = new MessageCommandBuilder() + .WithName("testing").Build(); + +await client.GetGuild(guildId).BulkOverwriteApplicationCommandAsync(new [] { command, buttonCommand }); +``` + +Next, we listen for this command, and respond with some components when its used: + +```cs +var menu = new SelectMenuBuilder() +{ + CustomId = "select-1", + Placeholder = "Select Somthing!", + MaxValues = 1, + MinValues = 1, +}; + +menu.AddOption("Meh", "1", "Its not gaming.") + .AddOption("Ish", "2", "Some would say that this is gaming.") + .AddOption("Moderate", "3", "It could pass as gaming") + .AddOption("Confirmed", "4", "We are gaming") + .AddOption("Excellent", "5", "It is renowned as gaming nation wide", new Emoji("🔥")); + +var components = new ComponentBuilder() + .WithSelectMenu(menu); + + +await arg.RespondAsync("On a scale of one to five, how gaming is this?", component: componBuild(), ephemeral: true); +break; +``` + +Now, let's listen to the select menu executed event and add a case for `select-1` + +```cs +client.SelectMenuExecuted += SelectMenuHandler; + +... + +public async Task SelectMenuHandler(SocketMessageComponent arg) +{ + switch (arg.Data.CustomId) + { + case "select-1": + var value = arg.Data.Values.First(); + var menu = new SelectMenuBuilder() + { + CustomId = "select-1", + Placeholder = $"{(arg.Message.Components.First().Components.First() as SelectMenu).Options.FirstOrDefault(x => x.Value == value).Label}", + MaxValues = 1, + MinValues = 1, + Disabled = true + }; + + menu.AddOption("Meh", "1", "Its not gaming.") + .AddOption("Ish", "2", "Some would say that this is gaming.") + .AddOption("Moderate", "3", "It could pass as gaming") + .AddOption("Confirmed", "4", "We are gaming") + .AddOption("Excellent", "5", "It is renowned as gaming nation wide", new Emoji("🔥")); + + // We use UpdateAsync to update the message and its original content and components. + await arg.UpdateAsync(x => + { + x.Content = $"Thank you {arg.User.Mention} for rating us {value}/5 on the gaming scale"; + x.Components = new ComponentBuilder().WithSelectMenu(menu).Build(); + }); + break; + } +} +``` diff --git a/docs/guides/interactions/message-components/images/image1.png b/docs/guides/interactions/message-components/images/image1.png new file mode 100644 index 0000000000000000000000000000000000000000..a161d8a61f2eaba566050f1f538e06e3667855e5 GIT binary patch literal 17256 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 LtDnm{r-UW|LtD*h literal 0 HcmV?d00001 diff --git a/docs/guides/interactions/message-components/images/image2.png b/docs/guides/interactions/message-components/images/image2.png new file mode 100644 index 0000000000000000000000000000000000000000..9303de91beeede1a90c4cdc8e6416f755c0938d9 GIT binary patch literal 19725 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�@2a2iMP%awMs+3f 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 literal 0 HcmV?d00001 diff --git a/docs/guides/interactions/message-components/images/image3.png b/docs/guides/interactions/message-components/images/image3.png new file mode 100644 index 0000000000000000000000000000000000000000..7480e1da90a413f8dfe8e13b66a9a2a8c5dc2bb2 GIT binary patch literal 40520 zcmeFZcT`i|_BI--(gXzrK>-U8K#C~6DkwFCKB<`Lby*1nuqYU3_G9U6SJ$A@DjI8`!Dd{7ne*;4r+Q|fs#MUf7~y}O2xLY3%f!uSAYNQ z9m@nV5`xR$qr$_vZni0S47u&PIPGNTuk>N<9ky5UwemDF(L1%{hjy;3T3(JCr{!S? zPlvCe#6LiS-V{az9K+II{qe!xxDN@}+JqXz19P%S;g=xB2I4}zVGtu}G6?rc%LP&S zv0sATIUChBER7*xx01o5k;Z*kg4@(zN3x4wcD_}J_tJan8j&gp_fgXX1>&c8gU_r* z6#F1AsEqtInKVsg<}4f3`R3XqBZ42G=KFt}h)5O>cIMw5GXf6Egc6EB_PoJt&^8Ea z?a`zk&O3jz^XX~ib?{h7fti5GL5%X9#A-~!=6^X3f+?dS;>D-@8pwQr>m~0xzgBQ~ z5xz7H6_KnlFu7oO0!5nmt6srB_CP7I;;ce0O=LcF_&^-!QLwYiQDreD@&*GlH35^q zWD#MMcbQDH`eP3yd(TDDdgCn}J})50k7GoapA3t5*vHhGGuRUxE*sD#dwRz+W z`?%c1*4O1QyJ)S2Y93&l^Dtd3GcWHj4LSI%dHbHwJA78ILgQxtmo357%}mg=8+F!W zRS}j6uC`&~MV!@p)0AeSp_rYmzQwpIJumZGx7`(za_2Ty<~E+H-!j9|+t39 zkM-s1R@xSR)VL^R)Z91gjJs>TJmUif_Nt#WR?^fjZQ{#oe)e}w#Z6MW`sN6}U}O#4 zkkD~sCVF?Tg5ed@UXx7U%7vi;6{#T!jX*WAQao6s7v8fFkrWWAvH>2XP(Wd*&Zx2J zIo_oqLa*-lk>s6_E3*5j+}beT7J7XOVMal5p=Ik=2FqJ^W9oijpX3dESfmpLl|T#0 zRx*2QztsM0&IH4?=%ZEBuz+Tttdp$|jlW70tBc&EoDA8zl6(|AjFUgQji$V8+o0_u z1`mfV;-?(+#f%+=9h||q~>RVt`_b(iM>Fe^F(@t zK;W)tVFe_%y$YrriA}S{Jty0(Lk|jQZ3^Cn>KTq*?aew$6mt@oGUmTX|5b8bq6Kk% zo+qS4qWDCvF*-fSo?pJjgC(SH6aFkHb*ry*lWv|Jn%Xq8k)9~@CLW`fID$kRTZTBS z2#P@5DOFl+Zx!l13k9}Ob*+X%lfYhCMEk*YCK+VYEXU{FM(Sg;BrA~jv{nJ4Z%f%Z zJEjQVZVY&FX-Rg|G~66{J3gCUGbe`Y?(o;jq}1PaNLO%7b(GJOU-V(yv297 z?e;WD1>4#sAzAZ{e26*1#X)aVpV|vjbpxBa@J=XZ+1apuXC%Md%$Ey-(MV!HsL~W6 zzEqk$=0UDkvC2Wovj6H$u=rbidaGVJ-7IEuJyA4e)PxIR;b%|GqHv;;U5gvFEXiOA zN8K#6?~C4CanYeK z6YW(AhH_S@1hKpV+SQU6gPopmO`~*$%7sl?!=VxK>%{(4!n0oPP!~{J03&?%CQYuQ z%=~R`Y5n zr<<2^W1>T$owOO21U?vz{kXKntc@8*@OLAaQ((m4NZQ8-<=Cu5&%wb1iTckyF^ocj zsC#a$h*EKH@OA1|P>$64uc=zeZ^^$x%`++ZeV*BDv-T5nuU3V_Hq2+MS1bZ?3WE3DmoC4e(!wU<@@f@+f}Cb=fRea zd~o1yUJnZ|l(v}8XNe|sDP0^J-(&KxgdPk# z;?gr}fya#BWRPqT>#s#+kbUM)^XX__^xZ*3?(nlDifb8j%@{H6rQU2JVXcwjsD%RVmFaw9LOoNYbM2rI#8?Z=L-(yZDOT@8Aj zu&{1oU_9cUR{Q06n`V01zss6)h5sHEcQ6`OONRNb{rW1HfY^u z=+E`|8Kaovs-JnFja9LBaZ^+@(ddlflsLv~Mx z;h4(;f7L8We7!Sf%1dV~hVA#beWGC}7Hfrkf}kSs?RA}&LQ|!?4IV2>y$P|p30(N_ zX6fd|mq@|EF05jX@WapB-?8d7Lfaqm)9n%v?F3^(#1C4kQSS9Q z7j>ykAXTL;sEdAV6KHoZ003bPXH3;Ej_$OB>Sl8 zP0mVf6?c0W*YZLaR3xu3wVfcELBmDp2i8uE#rUNmIT|c4N%i zZ1`S#p2MdVfPf8fss&eboTdFX}<$d;hg30K{kukr)5le-4<}GCi9b+hbmOVVW-l(1NO1pO0>G zX9a}3;eXacz08v4H_z%T=|rHiI4f=#25bf^d262hkly{LL#Ia%R_gQQxJno_{?{=5 zyKzZGch}$w#wXkH4l85@mj%0P|LM@ZvbsZ?#U9eUCj-O_;(T_i z=j%RyR&15}XL04%NmM(m7Zi_bEw!&yV6~Tb^{yV@s-9l(iyHmXnjiboz@=k)32iAA z=`meJTRKrtaS*!nOzV4A4YL}4(Ydz+;8$yjpO>cUB|aYac(htdJuy!>87YUFUZ6}Y zcyg2#U2N86=C+&I?pW`@JahaG+%t14&<+Mi1hvGsx>tGxu%O$H2DR;7CVw&;!w1Iv+Q*gYz z_OO+6F`%ClsPnT%RC?)SgDtT8iG11RuNw(`#oPp2x@H874}ylc?Z+bp7MF9s!N!kLZn|v z`BWU3GN0xhxL6xaYLlxU_e;(d0U15IsO_~ykX)q)6i|9M9n%FDR#?eSt*LEEoRz5dI0c2>q>ZiqRG z>lL{_Zne*bJbD4e4jJATc3?_C7cnRh+u zUhb}p-H3m6R*KZ^H4lg05EIR~{kr0>>Er#0LRL3I!k3?;R~_EwI__UwT_Ry9ktA11 zypV}LxbVt?C{sJ~EFNl%cXKSDt z_-Zr!%&}5Guv-*L=QOpOz2N28;9E{ViJiSTkanE*OAiM<;h1vFWcq`}p;PePP3pkx znhrh0CDZv4CBmeGl@YeAw$xIG#j@x6`uUwij$%$Lr1N8S0a_9a`SqJ)rB*k2OWV2% zO9C3RHz(m5QePVyT)0$$1BteVcpz1deO z*fOj~n+X$j$)?HNxO!Kc9@AU8(7W^PcFv<3X^6Q-^vv{Y2cE*}t={&yIgZmlXaU&} zXF#4l5q+j;nED)gtnR^NHa#j=$!+e5SjHfgz|4UNq`}2=CIckDV9h(xSBXk3DpxeR z9k_8dvmHxqVy;%SpB_^@p|4nY^MxP)`siLvX zJ=ssH@|jIzTgGC0&#uh6Ra|!d8V6pO1PuR9b7<(u%maMZ%(l#SL$bn>j-+}P?+@Yz zwg$nQr7>irKMB=2+xI=Je&^^VZEt#B!+8rl06e3G4WH>Vp5`ssBlH4;#dN4rS>5ij z5OwwM-BL|i6G@GbE5^lM9Gq<#*=x$6$}FN?dF?=5^;CIyLL?)sKJjC^Cn^M48iV(e5qpl8FJ#v`J zvp{}&^Wj868DumOX+?=;HcBuvqjtWrli_6sL&k}S%ZB@o z&8dr^nDcM<-vwTt+b^~1`A$pORs6OnPnX-CA7l>IPh1fk5R8hdcfn?&16uo3qkCvTp85^&o!SR=e4`ja8L zOKZU4jz*q}B^m5-`wYe(Tu-4|NaOZV^dXXsf9LtN4AEK@ziQ+u9f3lWm!tzGEtbT%>;0f?y-iA~&;s6N;PBIs0+0iVN1%{cDau zs;Ej-rad+S<9&I61u(l>KLO$Z%rd!W(#Bq5Hm6v`%`2KCRP|XJzJ*ySx@j?Qz~wu4 z(SP>y!dL3_p!cJnzVA4v3pQT!+u3^dYUFrFJA+az>X=%h%L}C?DyivgO=GE?8hgkjVLD6ZJ@@H^yLVIT|kCtD6Mi|L6 z|-)U=?Iq@=rc>cmK?42x+~^Z))U^xoX|BcHo}l$&nee_NW%+_!FcVi{mYpu8ZQ%Z z!-8Ec+(Ai6H6RxlvD>D!L#W0mbXAI4W0tm<4#OKOZ{>TRbeY5Qm8k88yEBg>D0Mk# z9h*X^I5KOXX5h6$$KJI4%g`<uO5%WK^o&mF+O#wEXffewttIx@=jLl0L}6V$1vT z`?~9#LrSFW&iQDx!eTc`P$ed+ECM#hw-IY;2O65G6ixwlyc~CDD$!>LnD3{dHRu2p z>uO{z1fN5Kos}={J9T>gXWV6E89QwsM_7*dN zImpbAqq{{uFz!L|8&>m+5ieyYgy`by*qe%l>8x*7Z`^1PWwt?bIIDf+REnQ=SYh?U z7i8g-zdt8c>YMcta-}2}Dm?%>R^);rr`o$L9U@~MsJkK1!1IJ+$NNqMwz#{xNC-n$ z$IrPNx~JhGh&ku_A|85#FZ`t1ZV7Djv9Uj)06d64RAnO*zHf5Vcx;-b;)hu&XiDZn zO;np-M%0ai5~nGoKeH=tI}pG;_rDC)c}(Sb5wk~4*~vsM?rz(!D(z>WvG#qtq}MRK zMnOqIRW1mEr-bsR(nv!|+vWr^Rg=}oh26?eB!LUZUPDQ5uJ@@ojB~o=YUaPJVUwuU z41My>b)Vb`!Ep~g1J|hiNoFKmFv7r#6+1!@xc;#NgAE;=Uf{8yNLM<%GVV>3FpPck=Vi2r8VGB!N zsZFWWU98PMu#*OIc3F65ePKbzw-K3RK4xw6gGCBXXt$?!W=D3L$!^TX4Y6f?#wv7) zaEy0}&D~TikfpnutxRdX!N;M@o7!!sf|gOuhfmSOS~oEOkFBAnWV9n{1C_doLz$y^O>R*};mR3oWSb^T@~zv43l#9ymOG!DoMx zEZsr7rrp;Ly8@g#8c{CvimoE)Jl)RBI^hkR$tFU9kUV1IDOJwheY z`)^4~Xfn*=;dQ8Yy>@W4%;@JC>ZBn26yLk)M?iY&aQI$Ls3C>9kGr_Wdf^UaHL?Uj z%!&;;CEK3LusNI_iadSSB|G9^J`$yR5eas-AW(HO!s|8}N>^nbs zTQX3XL2!F3-5dug7iU3k;dxzj0mf+f1L<+RE->YCyOsnRJ}WdipT!5|A%we1whf7L zzTAwCA$ZU-73T2_;$0y8esiNfkw?8R#pi7ySwSSX`l5Cy>lZYT+N3MWUd=LVn!Zg@yZZuUqpFwW19%1tJ**pl7{)_p;^R zpygJ*5|RcRqlf>{(1cN?Q8x$56S>z9#~T%0k54<^yS z2|gB*5ol^SilW!l2R;5)GZ4z-8syI%4k$7Pau}rt$lt2~HkjC>Ztr2-P+Oxa`-NG; zD%9%U_vV{o;c1UG#svOtLY*tn6$g7EqBBXFf5jkBg?D+Sf`BF?%TiR{DE`|vneD_( zHrMQFQ{Vlf3KfEcX;1KhG}}^>H?8GB*JhE?GkE)a<_9dHNBGzC#mK$a_G(fUIFt< zDq6`=&I`!S?I&(WkK6`t6hqMJI1{5AROvOYOp1kR5<3>z5^51||G4 z^S8GK^o8i6sed~TbOVaeJ1?>mqkp>ewcjLsyl$tu?!uIU6h!2+zt|vStNGGpYNu?7 z_ce{|nc9b|8rw!Xh4;{Na9jllEJg2~hvV$aD83gus7ZO7A!@=FR5pEz{mIc+NQXP7 z0Gq8JjS#$yb=be&=a-#AY0|_)uB|b=lGOy&**&knE#8<$Eq~Zmu$kB_vlu{UIJMbe z?exiEqG7e#imBLaI7+bgr7!ch($~$lCdyTOY_#Su4c<`BBcy}j*=gHWn9mXj5@cJiK0xp0&I~->cEJ*wfX-FgSz#oTdM?JD6mt+%S1!}7XQM; zHOu{bJECqV_tlN=8{+nLMLZ&If|mOqM)@C_Xt$3X4{EbnEmQ%h3fzj_JnjK$+N{I+ z1-ryB-^|K)UIrY}F4H{WRnrS%Yw`x=w?K1ITDBY3Von`g+>buv; zr1!rKsc4d_mdP|Woe(&u5xV7(s@z6IX#0dxMO-2N7%JC@GuK&e3dHi3T6WfL~$RCf4{%UZp;ggS( zNi%m}cvJRIhY}xC2yf5$H4+os5HO_)1L$@#@R1JwFV@Pmw?h0M)=I-)&D<#>`WiZK z$z)1mtA9F_;(+nhLMz!D3i5Gcad}(WKfD*3|Kh#0;6)1l;k|hO)wpgV<8$T(c}O#p zkNnf23|m5z{b6*(jPx}W&f(MNZDMbH4gekdJ98$OfX(XBxkq?^HR<2d8Lc5e2i}tO zCI58jgWom{+04A;f_%=5Yb-4Q)OSvfI)j@3O^%|upgi*S50~dJRDp!IVX_vqh3CQd z;-3yR@1F2hmqO6LG+Gm!d>9NMRA(!jmW9JI{@rQkxD;DL^2Z~9;`N7H($wMSN;1~hm0)sZYxj{8B z4M^uG9^sUbY0QLZW|3zWy1qK^UpT^=8Gq~Gy5e{ix(tUij4O|4RaxU8jZp=LH)@N? zG?u-~Cgnr+4Qh>Qb-ybM5!*Kgj~s3wD{W{3X#=GqMQm;q z03M%?@4#G$j&mmf{`ioWent$;QuL_`lZhPj(m1C28^DmqV(~RsWO$SJWn7^bkTMSg zd?!)gF96@E=viy1nNoDY@7Vkox1@hedf8+cFe~p&>F@42Rz=;o1Wff~ShbkoRD_abgn|2dKrsMD*elD;zT!~bwS7@^Sb!G70~Rb;;9m)# zHs=VTLLx{3l)gOPHGV-hBphp9M2W3xrGvaYyo_7s$Br6XItBrJjlGZQJhDvb?l|Dz z!9#9X4Hujf&z9wKdFx}0V`xp>YcW-vmueVD8lKMLn!DAwy~{pmwXt_MjUVGD&l5^&7Yiq zEwbafKQi}w|865v5W8FY3H_qz;g8t{cv_DMbEiWXZ*MNMG43um(K<=U8@)#fbA6)N z@C=FswH2nO?g)oSx0!FuZw%qzwc5n;UNpJ`)zXidc3+TOp z`Q0p48rDvnpxekXcxMo;f(2H+B9iEyZV?@U+M05R6oKi#TKDGE;CbD()Q;q|HXkDh zA~%HhC8;f^-V~3P93EUB)nuOs!9I>8Z_2m;9kc@OKkI3)oq%PXn$xZuT`J}uCx0e+ zm9l!kw1uoV#6lbvc0ZE`Rynlw-W@M6EP16UHR(2Y6tCAy=NHv8m>u0?bF9uS<-Rwt z1|U-Sw5z`KEiK-6obOf8J3b9mW5SCTf6OVzbjN_q)BXl8C46sZS?p2lG`vhOCMOld z$pba6(sWHMjw+D8mbAD|pS}rW$i!&XRD7YQ&v5hHdZVsWvnu9d0?b;y_`5E8>#=d4 zl_Bqbumo$x5n3tnWffnb*%Y{ap{@8AoD zSS)q$D?7N_8DS!m`$shgCrggI;~^ITJZv%Jr3Ygcw|`cqleIO;Vn(iKS~mI=1G@Y$ z5`;13)_2r8!xP3|wKiQfinGJs_%qX4TFQJk` zbR^z1b~^p)XVJODnDycO!S_I~3e}sa#7Q6xe*;)f6hC~J)jyONdI%M$OAEQV(0$nY z=tTGou2{?+|NRvo*27iZ?w^(Jly@=uHhn}Znh^?MBh~@@qcc%ws90ZEU!C}1;B;6MuCh7y* z>lw;bUq+t-a1Y`_Gy2-piGlVheTqtw7^Aov=izSaM4L+DG0S&m``X3dC$BtyZ+%|M zqYj8e<@8}YO#-0IHYDm*PwG5|r~257il1Tm(}Y zfXLnazsDSU10n`Lk{OkFIJnJJf_*{+U1H!v5r!W3^-q_Umm3cO$RR%Zlqm23$b1Y| z1u&{VcE92}_M*5YX!G20oN2jDoSjr(D}lT`vbMAHE261V>XaGM9k=44InY`Q^4}!& zjrMeXdTfV$M~;_*$37S+|LryxQLj?GJWITC%z#KQF@J(_?}HJA~A# zdN#_QVLIYtU8}-L3?e`?ZbHnc#uouRm-?jbmli4T2CkV`L*x|{2kTQFqn#b5(>|s6Pz^g%IltOe8biQyG9U!-{x-x(j7o9~@T5b|0EA>T0BmeLZ(+%B-w-DG zX>T1^^?WLCYNQ=c>YkT%g=XCRioeXc|_2ic>*=tW{ zLpTXijy8fmmUr1Sg*PfJuT_3(+ddSvUW9jL<}4OsH?b_OTQr5`icC3CT#N+@(1NJc zo)m;+bE1|aZbQ=Gh0^f=*J)Xk&_#8-f&0vw1pBzve_PAJkxTGWuDk(rFZVH?0H9PM z)K|@>9tT+*1cYA5vfVMAhpaAy8Y^hq}m~{Vfz4={|tqqB}zJCE1&hAH!wZl$7 z$MJy-tId)%dHx({@K3&VhHNYxlZE#aD~;Ga#FL;*7disE(kqWx%sgPpG3#wE1BE!W z=$7llPiF@cryzhD8>}{D@9MGusD(=&TvG@ImJmya%vE|ym__Z%UIVZe-%!+3Dyk@Y z+4M_Hsr{0ae6`oNPcv*j5X$1mQkzXsp8CG?+79`3U$vmVocGJ&$84ZqxX<1gF=Bi% zGC;xD^_m}M=t36aiLrcdF-$Rx9gPRskTn-c@|Ned?=Ds#J^bQZ*y;)zXDSiDlg%Paj)y)I;Or(uP9N8(Go@@1p=&fP0&XtVQmXjz)xLi; zXQ{<7@TtReGKlmw@*uN}YGC=k;=WJqcgy381v~uhX}K%xc1%XDB41BK4qo+@d#rP{ zA15HE>yE1-!|TPX0oY7*FAl>%sxaNH=X+#c>fX&83QDOutzX=^kJ&+BpOtrk zx7BZ#-t=?a+GJAasm3kd%pqf`EoWW1Cu$cT+R0enRZmANH8UF{2UZ!sQxAHyPa)4K z6ON?(1CC7Bwr$Sgpb^dVnrF)_irq!q16Deu^|g1x`z*WOjdu<$%f7MiOR914p5KKj zEt5+;cHrP)HbiEEbF*rSn$Shuc#5>u(IeMfgBR5GC2=5zHq6D;?`$(vALkQtXC=|y za;%~8bW^bE0ZbywCEYQX4BxdMh$rPHw0(_%w`QYV`&s%|Q_roa{V!I;0&$d;C4i@; z@bxgYe03h;&f)x3EnarJS|XBy(;;lN{Di0e3@*r39}CThZtRjZcig;Y{0(=n~{-YvZknYCKO>tR!7tFPY(N`Ts8@?-D2>xBG(Ac1On=6sg? z7|9oUwXTr0TO7)B7Gdp}OqhW!Lrki@sFusifj?CSPz3&GGoI3O{gZM5)vk&0rV_7E zOfN|sp$Ndqx{9+JeB=gEiq886@BG!lE7VJpY_0deI4C*#ceeNqjnIX@Qt7s}G|O@s z5M6ou)b-4Icmd<`d1WWW5d9(JET))lXZm*eGsat&WcAIX$-KpQfPrntk(jIyejD6- zHK|=a&C&{=GwQa{YthW@D-XGQ)LleHlk$la{n-uN+z#d)s7K~rg&u1pugr9t>`oYN z^CA&fU%s~xp+lmFbn;j@DY-WIYRl}j*lZ#iz{KoHWR8Te^*d?b?9v_-)KukF=Ddu` zUYpE|8}jB(zpURaigJDv4BYz< z^ydl{P>H+aQ<+asVj~Du5G&TmwtKFK zO0~|KI__Mz`dN`p0>goHeW__R_~>vO%NY?42|Zd={74n|TgGtY*J^3Sp42_qVHmce$bif|;4Yq6m3CL(K=!UyD_Cu5+jurCDt+3_!wqF;QFu zEan`^wJNUTKqJC3%1pYq(#a)#)>bX9;$>rGZ?Q&!w3O70+@~e9s|kE6GxrdE24Fc- zr3d*+e=DG+qXH;GE!YBy%5MR5bKCb-ZBg!Z!XYeN%&Rrm533VatCHL~js*L_7GA8^N1J$r%gh2qBJ;StWtbQLib!LtlC0^H7_y=&$B?8<=()o5=LbCUfl} zn|9+;M885$*^Hzl0bjnKa7cZgJ+f?R_YH$_n5F1$SE5;E(*<>sC64{l9S;zjUy=x5 zyyE&gwZ@UL{w!YZGR+qW^jk?;JS#u=BTkv2pl+W>{vVusq5x-Z%CY)vbh0wGq`G@N< zMPXykG7gcuIr$xHPfAZF*II4jBR#gzmgvQRFOp;dX7uUl;BG0Rog~o+0D-xY`Rn8; z=VM8>h1h+^{5d&mxt4eR?H=D`*v|l#Ajoy^1hQ~-zpMD!In1Yhk8G4bPQ+5k==f&l zB<;DEg62-^fte&vvKiOqJE}RT#Xa0RLrRIk$E(Fa%l!cj)m``fsO|Uayy6KYsFl;@ zz9@X;vT9)=cDCAYJQg8sLcd9h8ke-q8U(RcgHptUX0%6bYI3{<7P78}_PFhB?|kw5 zkFK*g9`s+L-v4da`R&y1t?qy=%m#OIw0!-kRv zc}qS8?zKCIBW9?MG=+iD;bLsjo7I~5W8+nyrDcgj%X((lU3oUhLd`k)ZQ)BanN54$ z231~hF3Wg4DO~(tz)R!0QkZAXU#g7?vx!FCH@KG;3|vjIt}*vK$4`oF5UL*y9*C^;f z&mj|CF>e-kb2b}zLFA^6i+EnY5$LS0`FWb^3-UuhBnJP ztMipQ?a^OM9R)X4BPtyF3@7KxMo~_C-S!g&L>{Dp(|PWGUH%#Z+4-bT{7X^iss(x$ za{^LwT^y*dNSiS2NO1rh$=d*Og9{TLjHF&uLZBiWE%AndCYz2(O${d&daA9kEuMb* zk#iIu_{pDNws~BFi%_Z2k*1+>2x&U0ify&p@#(x%HSi(^&dN4*jS2hB>+nT8RUCo8 zxsazg2R(L{%Wb)>rMlD56XS4tPX8!)SHP54HnSDs*&7_7G$^n*3^2a+tRYpIhFFhSetw;;qIvUY7x)h^2ixK~r2xe}|0c}~?En6=+Ot0p_| zj@u;I=?O-?ma^@j;GTcil%e)q$9!~NaAC@n;&roj=ZD*JMF6}J1rV|L;&Eb%r!8Z{ z{uGQ66;aEhP9`z>8y~v!?=U==4gnLSoVbjx7C9T9_9a2)FSu{JDepVd_|5gfZ4ESb zTO0VsHX}1tOxHd4zV&b%d#|EuFX#d-eMq@S?d&-*+>we^zRf0Ey1h23n)d;B)Xw{Z zJ9*?FSU{q%E&t)r#Ic*>r1Z=MtmolrZ718$CNG-L=b-zo0bf)TPCU|`4vDPKfXZh#$0LdRhj<#QhT;a+L`rD>KOjlgkM5-X z1+euQZL0E!Vy&wjjQ{-NOag_&2bg6rK%pT#`uUmM4;*4u28fmJ^uIdv&a$WirhzFL zdTr*h5t3w-IH;G^XpTHJI@o`A+J9vbqH`=y&7jtp#P2QJK_gvxH_>v_Av1MK$UiH! zH8kMJ_RJMJ2DN5@2o1)I6iTFnFfh5fL$uX0?Qx=>&!yDkPg7LQ1`5-dDMx<_7oQ5MT3q5?^<}P8Mct9h0m) zq+9jdZPFR98v~-+Rw9Sl)KrQ&r@?oy%4RW@ptZdo0Rb+(>z{Sstcy4diIIG@Hny~Nftm2wp1an;W9vuI z(&VS+;YvG-u7QvD&5CAPp=ED548E1`N;@9y1uZRA+6`YY>ok!Y7dt~dW`I_OJ{@0eC5*)KB<2X%|C zOMte(Fg|*79@j}1#I^L}Ym^k-x{}-_^||ss$>I63$ROKQV~ynjoB-wKslL;0XhmY` zzU$>7h1_qaGbA0deiK8(gBU-^9e}Tvb5{SxS)@vvb9cqb9{`jR*jmb|WX;Q)AVw$zyE3-g4@oZ1SY6^s!_E$TNvx9=LIe&^-f|50h zPrjw$rU}HlU1htJ5Rg4}aS(8%TR_%RG zf3Vn^L^`B+2;2>X$!gxwrvfYs7lxU?p2c7-O|r9zcn zRHf6&ZWAr|CUzs6>0x9i1uV&M-zxx+V9*rOmO617YYZ#tP_cGJHh}$aMU9c9&`fl^ zmUJn8N~JD2aQj7X<;{f=9lNH|2BrCeI%~&1y>$D&;j^wiiN9f=6h0k+JUL&4%-W|y zZaoIWEa5SKiY`+e7;j6u$yRaYE=O2%l-7_hqm}>lH}4-R&XbFD#v68KZj_Qt*6nu; zeA17~>#$OH$-2S`%jT0-sn zvmL$9aahf{cZ<+`vLVDJuu**H@fR0e+C}I$_@@+btu7mYs(evRD@kNgTqo{2M^t>? z1T=LpW+9>57jd}Fh}WcQg`+24{IuKfVXEsv`rxG$aTt~M54%+BEB*A&8)IxBexqyt z`k}^8OgWU-rXfQ-eMVOev6~DH@nMKhtFa_T#R;nv)D1DTA?v=;=JV;?$8@t{_hMuIVeZ(x)6bN^qCAA$ooovew@>fab+cre0tE%JKsCvUnBF2} z!Lf<8Xg9L!b_f9INN;_o^omFnc2Rpcwa+d^kd95DDTq;d0r+f4{;7zGOFkyyG}02r6rh*83Hg!g4hklNqx_y9<^$6Nbu0FMR8ewq{_tdV_$MiAWcNF8;@#FPv%uWCO@ebl;BD~)9`?~Py6nxp}VNqC?lKx$aq}e zB}o|Y5J2J2vJ>nFU)MQ>U8mr+7xp@F@Ah0haf<7bo)=+nStPnL^0y1?1q0$C)qUW6 zI};D}0qC1e0Sy(c3CA21Xe_gAV)jP2b5YT4+&Y8KGl|45jnEpB7v#4Pw=$i5f?4EU z2+jOiTdpP3VApO1s?{{K&sAExrMTzqt%?sgo4@UhD!3ub(W!KxAKLUoPv9FtkA1!j zp!VspQ{1@HQg9c@asX}3op1cI*TQLdRn?AdW0UeCE-0;!!!r!8<+sJ^uc=c4!$Kei=l< zQ$vP0`YJX*g+*R3*dqSmyq_d(+7b74vqaa?Oj}Ko0Ew}4zAVcz&cqXy3FrqzH?4ve zHT8kJEMc{0?rqavUy8I)_ye7|3RQ{BI|c9~%xfw3^a?YfWAy$N(kM%5wQF%dvCT&> zqr|m$q5*NzUi&)pJW&ddH1e?N9DM`acAEY6SvlM^ke`L4e!PYq9Nc{5rtaFFgi|M- zyPfOl(yIFqE}rG~5pn%$l2fn^-4KsBPxgeFRAL~;g^oIwFWKqN|Pg3!<; zCFdXlk~2uol2a3!%vX)NpZ)CjJ7XOGz2}TQhQFk1)mp1ot*W}`J+E2oeX#B!+=~zV zu~zm!|LC)t>QS{s?9{CHzVQ(x$wd!#lSUJeHo#BKP@B#pN?HAmB#^x*1A?iUoG9o;uz$+?`|j zTn>so!Fn#d85WP*fytl3vlavUna5N7`tJ-7bHN~0T_H{E`6YjZ-)8{La`hA8JZ*@L zM5A#`$32zRIX3)|Tj^PL9^#6MB-rX6{A^{9!B(3$HIG==>)~rfKQmdbzUk&}DOlQ8 z5LoDBq()tT;*0=3mZx)I)W3dt3C2kEnN+-r!buL{NoiQ2tV!xu(I?FV!@o02fV7OC z>O;&`{*tEm0O<}@7SFGcJixc`$o~~%VjBLp$Q}@FEXBpfNpJj>Ujlu5eP@3Ga+S9P zC><;eR!swHKD_XIZjZB);Y`D(O|3a`>Q`T9R)KdnrTnE>RDX5m@zvn-QLzzRK&b$Z zg@f+oC2Bu~~ z6sH*vbzJ@IUnbhVZN6A+n#`xln%?hy3*00mO%gi)b#kB~Kw83+E!+KKAYtxf>f+eK z?3d#*>w2uo%eIcoz*aW*;V?~-e@@;}{#t-X6>M9qB%Oy$=%{B-!H3z3N@}fd?y$jB zTL+go=MKs(y!qEABCoI$2yTdzx^&jI0I`b~YT*J_T44gp4mzgvAGJpPT4mu6{Xdcm zdM#Q639PMiObc4xv4xNKq=<|n7%Q6bL`^H)d#5phL)Why%&9r}H|#1c#p!af6?vNm z!v#2VXwpR8<43bn&rLwUUZG$8Zquw77cUzYhw3FL+-IT7V!Kzsp#-~X0HhM2E z5n+4CW*bZRATynhU^J7a{c>+|dr#fDi_6x*Xo-`EYw`A2bc%#$`I_A$xHxJj_4<mzJG3?Ox5_h8hT z_!s!;B=}~@kycSS(zf%hPV89ABzsZQ=}_w_|8~b(T|ll^J9nB8`*4P&8o{^qFKlnL zLI~(`aq08(i&_siEV1!w!BWwmD`pDwfkzb{@YrEXx(DMCauWFsfQkV;-cd`Q1rQc% zfCklYpi*{*@|y)>1gZiop>x5z03wRI6DfSp(ChpFUVXdD1GV3lqcBc~fzd!z`-SZl z3M#`8`*U z`}XiSK0IukG_(bcWx)J(9~F4GqlbC*VC{C2a;C3^Cu>%`|$5dBccBRRDYKXG+8v zCJ+js7`t^9OOVu<3+&WXg8RdsyA|KR>K8fj(^u(|Q{)Lmch=|(W5rNWi>QKs#T0C( zBh263T;#rrK>Vv|lE=`A_TdeAu)++caT|_QEiTygDjszDnw>{Vf8V1% zRX49Ge=F^FGcfwAgzvnpi%VOCjm_mnAEmj^`Ff$`+F~KWpg>fGNpjVc7wF*0XR*_bpgxzf;UorC3m(f7Z zIT;S`y#o8lNW2XVb+;C;D6*?V`>mQf{vD$aibAB5Adagw6*4D*o`xh`(4> zg>*ui27wOF0r#4~oQW`5sE^E0a~>Tr(=C~p@hX$!(A06U6i?dMqR0Mb!lP>-^q9T1 ztJs2y_onr2TO#nb@8#)l)4jJoP6(ETZfPmLROi;yalf?tsm{75xm6sErTcNm97d+4 zPQs>F`PgI^*Q|~JZl=3kxy{)70{t;RkpH&;Y(h`9tQpV&z-iWHP#~V>z8L$izF?hD z^|sfoogalEU;^WW

1A#5)7Al0Gkh`E#N;jt_EPQDyYS(z;4A_-UMbo#TcNos&;7 zwvVY52XN1X=UJJBV(op`tAQM=;7Wi+Y>L6NNiqnYQ)obi8fg3@da$K21Y%e3x*c1) zck$PMVvT_nFWx2Fsq)gyKU1Jw)}+?lwk~?GrgdKJqMM~nU7DK@OVypIWuDPXi8!Z9 z?l~Xz#YV~B7h}Ca{+)` ztuVej1PTUGQ?EG1hO3MLcn3c!Zs3d|ns%Ss*+<8VezF75sS#c@15G0X$ zMP0i33aUO^Lu1@ZKxL!tji)ir_T6tR7I@@v=g4De*mf=U#Tv<DoopI-#j-Dh%E*#zvZjEzUv3M zFb{cg6C=}f;W&=-^vP46N{zG!ml1Nb3k+p8XTtYblPhwnJ~}*ZD$#nlxlR6aBjMV= zbzzAMc02-vWNbn19I6N`T8w+1fmrMTAgMPI%I1>SDp~3xfU9YV{YYF}V6kXHR9Jfo z*f{N_V+twmgWm4J#bfgfkRO5n*0sIwItf6N-Shx}C{swr)Jl#MQ9%$e>&ihgX9&O%lAj!iJu}~RGmAE z#9@OmDAAt~J!GpPlVz<3@($WA7gYj;s8AC2ij4Yl5KGn|kf=asP+z;;RKe!Cf(4pt z#m3V;S+)6qW(GE9g`zz=7Ln2j*?ukrt<`~N;y>3mpsv*cwhN;WU7m$jxfBSATX#NA zrSs?fPg8YTDCERKZ&Nj`@zYQ-uwx}d$Ft{+J5KV|BX(Rm6?Rjv;veC?BZr+$6WteP zE0SzmVy`Pd(gm<0=?0qv*`nh_4j2OVj*!=5e-EYJ#obwW&8cqGz#|+5*5TMExC!i^ zsThs2svj$rK@{_C(5kIc0Lql#H;VH)MI^9|m71FHok@r=@^mKH8a=7p$-eelp=VW_ zsw(j%8aUo?3XABVA%2QtEP&zhGh?n7w>ZN9;?yppN%ZLJ=)<(db|tWWvi2&GdjKP5 z?D$5lT}fm$WxQd9aS>)TfEPohM*PlkAS0ESqLCIOe`|Yc| zRAdJil~51Y5Prt|31XJakkbGCX)eqCp1hYqqD@i$3brngiZS^qMT3f~go*L1Nio>R zpz6shZ|yuL;@175O&}ZI;3dtO?vSG7a9uUrGlNK}aAvfJH^unpLn4^P{XNk`oKU6& z(K3FwM8Mn%;Vx{?5)}ck;-Xq>8n2ZoG8X65>bp7XXf~veH@OiAsg@e$K-IG@^^$@G zMa+e}-fTmb=VlTHrw}gL;9W1~ZXAyTz43`1|i9!PJcUj(XuSi>NU9bk^P=yka zb0@HfPj6C$0ygbOrB}Tg;0Mqzv+im>v3ZDEFV)?`K?ZV(J@SfSOX5eu!UZ!Mu=OLK zmypqJ6i+H^>gslFK|N9AZBx*||2TW>Le>eb7}&!_0n)Z2l(T~ft!1{F+{2PRuoDA- zof6t6_|BV4PTb$zbdn7T(yiUyU-Au6)o);{=|GswCBwwP5W1X~9_1ZL3<{t{QDHbu z7TKa3e(C_bKBNQ?r&GjK6=3{qPnO^`wjG%c=W=m9>v*cw%P4?TZ0d;v8EEx2i3k7V zq*Px7ud1$nzMI5$OfX9Wm9*)tFEMgxS@GZ;ugz*L+Hw7$h;hFh&o5zrVaa+Jy^0%a z7oiZ9^1-p%Mc{CSqaanlQFr`?1z)Y+WJixlwIwK0HauB%pk3=j)E^UrtUa>)at6dz z0*pp?BK?~D=9WX}tuY@G@jz}c7ez40jS7$Us~R5_Q$8|f59jwRc&-u?kIR;lTJVAz z3yi_E+z(!2N#W;gQulb>X&o2LlBJ&9IrLt}mQ8z!Mc;kMrA%hoc}jEySOYEqqfpb7 z(w!l(r)(U)uXF2h%>s1b4ps)bX`8*y2e9rwkmpk%`YqhAI z%6|V0Ck7(Tz4gWlP22%el0j!&{zUi8$U6cyC&-F&?ZciqUH?2&}Y}*_LolGo)f?l$UGhyjQ_zT_F zgs(ywI=EnbyWTAaY|6HVCE4{71M8o&<1;rOwt=Z(^PcO=$1l@Zq0DxMZdHL0SGu~? z$s$ow&L9v&cmvv<7-Pv>xS!)b?am|-*dJ4062tpu;KpYy*CaJ2F_)4@2{N)V@i*gY z+ecdM_5HmdFr-h@hS9412|m879csXaN+&_nmuS|L06I3%0hjn(E&07Mux%>ZA82H zN-%dly#3e&1V$eHbk+Ul1sTzZz-^rVQwK+x@z}i7jR3@RwakDC((s>B_T6_x#s-@I z^JJ*+`$*291fus$VJgISa4VJH>NnThXX>U&|6_E&zKri8h2H%Z<~8vDYJRG%`Jb9M zP~b`PKnaPGLO^sujtr~vKx@GwWH<@!wX&LD|2db7z84wv(1T`uGhko{-Cgne`?d7% z2DkrB=a(K*I;pg45h#7VD*fX$zs zvq89-+S!)y(X{&#U^IPj;id5Vg0&uQ+XEaWqeGh5VHfw6k4mN!A9xESUW5s-QG1>r zpa7r6c8?0~Fu+@*V}|P8>0~{z)Gi&Sx^BE2AfRbe> ztENYWsQUI}#xOtWTeGZcwT za*DzY`OR~T%-Z+e`BLUg2i;M}=$O1}U|FwdQZ95XND<}whHoyaky+2?(#^W<)wcKz zz4IO+9#vJa2B%37SUe{d9mb?-*k7qY%e^?GJ}A&&u=>Vy!z&3gU9l=K%}3umi01(m zJ0LfosZA?4q#{~amYb0iBarjIttLrFP^)s_$8xY2ZS5;4JMvf^RcfG|tkWgh_KWX*4>BC%Ge!#2#Mf}9XD#Qw?&GLa|Fph)k^BWbI1l?C zudAlr!bZ#L$I4PZ*9|uXE8YZtbXAQ*^Ps?;Hm=Aqk_>tZ?``(z7O~0OXEvS8_G4D7{i!bWkmyu#JMLro+lSF z(M@G9Osr2g)TM?7HLqpqc#YDNitUT;HA9~q@trM&=_Mlf0kdTy2o_d+V#RhSHEwlD zzvodwg^oU`Hv27#(O_wv-$46yR1P1uuu{2t#9&^vx}Bkb?P*KcC0{!ICE!B`n&6!9 z5xA{PITbUelo%I)|47SUS8C|3j#Kfn;dk=GstS%oG)dAT55AWJfF`Pf*Gsxl4FL)} zl)G-%f1+#=$)9+sZ1^%+#2%dO(&l(OU(qjY&r#eFaBO}(v#&pKV?uLVVfP*8>Ayrd z(+?+G0b~p1u;=_@yQ(rcxq0h2y4PF**+uFzsrjLYl79PmV_6SDg3+F{-_NbW zMolRV_S0>e0AXHy7*n^(l4xNd+8p4^8V)h9OipFHUx0JXxnGNB31XHRZet_M{{~c*s^4T(0(h zp<9R1w`d-vdgCV2#@p|`EK0(D@xB%VaB4LLS9nTz&R}tI%hmxk&hY0RM!!W>r(=<0 z&?MjfWH%_}eNl;0TvICxNYp(6({1WF*5~;4$~^*$Qtv%IUkP+&EGAqMnyzU#W8^D` zgizFC||_<(@|psTK9@ zJ~(4M09#@t+iVLij(g68dq6-fdF>4$hF8l ze2Y@c0s3IVC(~jG$YHQIF4L1)gQYFfa!wr#yI?u(GSBESc2LdyR zpdTkE?)QLh^#1OKD0wS19VpWo8n=hq#n<fdW5sUb34O}hQNZQtXSiZ5HGDG^rA4Y${JqB1!^S)Ya& zI?xXGD1B*XHO5~K*s(cI>EW{C0{h7W5-=)xUhvv5n2!~Q1AR00r zPEGAD<`^=_3IJ7#O1n4<7yLOzhh7w%MAC}TAy$sMPUv5Yk?ak~xPKp#Yq8W8Ar9<- z2`^P4yf-GR@@{UIkL(J@w!78N#Ne4T7si4( zg4Tm^vMlo;jku1!s%J{8^)-j5WPabA*=C%m1+evm9p_CRWiAE7RgzG=e9`^b2D`W- zkFDbksK7+Jbu4=y_#8prvg_z6l9C6BjaDJUjG1_DfUtx)8OV#!k9d-_0tEdOhP5$s zfmciJx?3>Yi!o?&YA;?Z1bsAJkJvW8a)j$&41Yt|300wK;SOlextKRrhvGh(ECuO6k;2 zx@6MD$U%*;+l@}UIbeG+y^lrYjt?ajo)6(#%u-s!QjU^wwC?Ft@VIcofa3@ru{f-63 z)7rZPNP;(#k~=lLK7mq6TD8< z$gX`@o|$L$Y4URN#UbxrvWf)Eoc0sKrMA9eEDtlE>U_%tlv*@MknyoBO~$!)67R^S zheuktes*55WWj^;Dd^ow6%3X-Elk2ilQFrau2;TRP*7)&HFSo1vo>-%dkz1SiFV^h zfC_-YzBx!Pv8ir|<*th*4=*x?FQmoMPP#&-eVE@dinxb#V8%e@yPSy{n&cknup`T= z3-qL7RF=u!TI{}!3{(*$=6c0g!K&JS3aHHRb-zsHF~4ZuqOFx4!=i0Rc?5ol7jy$Z zsC1?B(0T#@^ek<k|7W|JfR_m9*3sDS;iQmCT5$*IS#A8SMP3;n3LU~ zTOX18Hc)qDwtf$Bs5v@uuR1P8RCWm+o&yA8+%I)tK=rW)=&~HAy9gq9OkMw-BL~6j zp9D+!02$es?2NCdTJo6LS3nlT<`GFl7;h zvxr_z3$usy3+3eExP z?mvlUkT*s3Gx9s#>64g4cX}CWBP|7Qy*eY~k)Y{dzvc5Dq;rPtFyVtdjI<%-5%71&3h`Ab&GaCvlqXV1zBYSs1LQ3RhHFnaj#_60-&tXS=Qy_j z4?8pvk*^l@Bqr@%a{cn)Db3_!!|fpp5gggqi9y@6{LS7|wMEgs$djrQSJSDH+p_rL zr3LXfg0D#h-3Sf`Li|s6UnE+^8zMjy<(w;s>hN*A(@$pI-+0yM#ETfI$P->SuzhDC z17^tf#HGI1d3?)^Ys=YKI_8-ah%w>1h8uOg9Tu3ep%PhM;QvcQK;S)wiY zWiE8!xd(lNjjXmYmRdBZlnj<*s<}2#;?u}z} zVBS?C)#+(6yw;$pkqG)g&{O=xA#ZqH7iuoeu=UXE?q3qgDAJfUPBN?sT2%G%I7F;A}w8}=?`v; zZoT{Q;qGw1XH&w2CV$82>hF$^_7TgeR1NyOJ?*`%z;L^=uaozl)i?C!&aw{K+(JKj z5aaAF&}%WE*AW|{<=bs{fSn?j14;)I7nD67k`SX`lE6uK8A?6LKito}p=+Y9PC9(q z7c`9t{_xisD^Re#qYH~XMLGtD9bVMZ)Pl>^A-dW|_vNAK87>P=aqU*N5~J!8Xz4Ov zyA4~Rn0kvW*%G=T^r(u%9y7#BeAZcT)ojy&9AfNi_UIJ2Mh8o4*6}7kOhh)4vPbY= zd0jihOFKJeH4VplraM%K?7pqAvltc#sqBT0>bj5CLGEGZJ0t=NH-N>oXDCvu$jgOe zC^H&)F=jG#<`fmmpQ-$`M4+2NL9(A!_ObLZDSDTwrsr)M_nVue^E!XcaN-f%Rv6r+ zc~?4e9o4lcG0x@kT4DyaXdv4!INEN6MBWJVqU+sZ86kMBQ$?$=r)vpzfdAr)uO$1? zwT+`a^^RMX(28|$rx4wexu}hV3&EAwr)Ta3phgqUWHVUxXND-Xp#U^A+L_0)QW^>$ zcn>m%*`WsOKXh~ND{ix>vWFygHTkPhcOj()PZDYOiiJ~sf52D7E1Epc(mqE^xoJAn zyiF`yeikE9=+PbFK6bV%=X`5(?}U5gc8=1%^M~MeyYXcwt_!Dka3->2?6w8=S=H!@ z{3mK9#t^Nxy9i*iEtha=az( zMXgB&_{0jVtebHuPw}>zw0k@x6<1mEPJM2j^kVj-J&S5A#uQO&u4i+ldAWyFG~6r9 zrTVInW9vDC+(wfs{LsU6Rz+d~T@POWsG+sl069lY$kKO8u>U0uD&G3KY#KR!l8k=k z%W_&E9zahmEyL1kZB~FM4lxrsWwZ3@qoduupSB;6+Fj?*mLDdZoPLB}0Ww=d>O|BIGRDlAJ^*tH%0$ z>_2YCC`euD6&$iDqRac^CeN4x!m4TPT^Ur4w~TVsiPiDm?W1Ee>G_{Ylwd!d$50IQ zP%iK7_i;pJjKj-8&I23nk{aRJJaiJ)%C_Eh>hC^ud9*ZB-32rSilcr+jR(TKTK!ct zWMvRoZ>xspTg|+H(Jg13hbL`zuFx-x!*+m z_W*1^5VnY;VsdLO%5qlNDMjyC@*`F7&0jEnmWQZ`#>m(~2abN!gRAhyjq2eq!u%s( zR79!osYT1GMY_3*DUT$@ycpEpHWU5gqsL_Y6l9Lj#QjMBTE@(h6@B}giT@XHC9bae zH@+dp!A9pF!W9VrN8BX5zi|Ajp+5@*%wYmYzf1lf!=(b;u5MP&u8GDboICy=M}OSs zD9arAZ2$ExXS*fLsOL0hzZ~ajNHF-HTy%`F&l%3vgV2i7g{&Am~d590b@j0Ya^%VU1&7eD#@`GxO&?}AZ&-?tp@&?wl z4oP(X`q>58Z(R_{gPSo`<~wYU1If&~xhWp@C^LsT&fVEeUskb|2F$7~yeb>n_Ks%Jg(R_6-=lVG3dpcAk8 z!`9}9&PsYPKb{<8QXEeLJIsUExDVzG=6&3J=P7?UXcv90@d)SfWbRJY)AL;q?tK!w z3=$eKBEj}h^Uo{NkxqsSDicE-HC0XsQVJngkC@H0@_q)W_tNyPIzPO_U(ohoi@a&A z`8G#}qz3^gx+DB?_`W88C^mNJ)q*ag9pXPhm>3?T6MkAX_>_wnr@(&}BjxX-?U$h8 z^Tg_-W5X%MGNt^_U6n1Bt#5^}M)?#@6Edi^jiHwe3Z@`mvBh2^r&bdloj$zfVHo>! zBLs}uJyp0i9+WolS{F@hsc|X)7>Y;u_tu8uW4r_Evoe3~wNba%-j}G982X&Dcp?&2 zCiWx}?DUF6hPJBqEov4w)Y)IhYG6WQF&)R(44x@6KN%n+PY}iKIH6-!E=y$+bk|Of z^8{``)RuooY6#oBtE6C*&dPJNw={i|a;%TOsA4Wf(e`MG+IFRi&}REYWn!DM_mfjk zg0^)6#;@Mhkw02xCy2?CvAKGuNwBjig@5T;ZGGgY;(V8cnuihxpj!&$+ zRoILKI__#dF{4HF9ou|_m+^tlXp)O3VNNI(SBFMkW0HNnj%{G+jZHIZN4TIQI@oI` zlnr<}6h3q+*{DCDZmrY0m``0n+gp~nY}r>!S~hfusyi5wu$d@dZY?XZI}h6Uj=bUR zJNfxepm@_LE6m&SiNU7Gd6!e`2K)0oJJaVAQA^lZ6^Jgm6iFbMH+hqV`8n78gVT+-JZ9EwbA*)xW( z|1eLsH{a3X3pvme^6wB@_A;GZpAT!ecCLY(*v`z3AD=9>Eb-n6ytHbgMOHa(=12%1 z4nn87x1L7P7B@I8_i#Tfvp+qgH9q{z4e^(oNl)2eR7M9c)P;#np@x0khEEqugd0~F zgIOy2M$=og$BLOQ8WZO>gcOFg)4DUPGPn+d! z#<~`C6do5E*griIM&=QY7Z1XTX+7N*GId0Xfr??L(92Rl(z=xu?z2PNlg`U!C125n zZha*GY1g0htg|xy8S{@jA=jvK3jnyJiQh+L`1rM_t52DMDzNHPpdK&7%<|`{#uDEX zS8A%iInHZ%qTN-}QB4cM06_iJag!z(By}C%#*<&H#kYRf6bZ;XW55Vu^W};govaAM zg1+gP6mg3owx67_>Et%k6Sr^H6E~M=SR`{9-XI-QbnWKzJb84wSIxKqAG`O*;-zSp-Ro`YSX*=Gdann%PyCn9Ijz`B^UATbkFi5K*wv;0@_0da$90%r&YEaBgae>f@wMESc=vsO z#aO3&B`KaLu{k{Z#8U4AEr-O#E~4LK{Bk~w)AZC?w2R47kJGfFwm$p%j|rlQU4Ac* z^hU)~uUpS5H@Bw@Gz;hIy_c)p+Lbbw)5P;s*1}F;)k*vkW^9>6iRH~s?Z_&_@+9nJ zmqYuSEl^1tY^*Oka-vTL_xnyX?)dz%y3Ik>=~&>*Wx|*}?#8IL?^i8fPdLX1iI!=f zMKo%U6*3+7;nS)2GUEa107ToZMRTmQ27894YotS?zyRsDRB?XRQ#Wf}?lKj0FEcCG zQ{t>BE7QCGrMS}E9#Q;sQLX3jiep88d$r+N@E!{##(7PF-8v`(>%p;UPjZz`xkY#4 z105H69Xh3h!EzpvaY&^@zr}-1sJORWxnbLO<-$3u`}l~WZ6QQV%}^bQ2m>7aSCdez zFuwdD+hJlRPsJlwKhxVMH9)SSNIY*_cSvFrD&m@&`! z>_O-9?XtZb4q2glcvNQ}?%>`s_zN1bOnGlo%e~Ia-H85?<-}Z9WNxy`G9hg07%g8X zsTjbzW{AVRD!p5Emfs%s_deWwb*@oo?`7>!>PoMga@RPY zZ_`z_p~PZ*!;mU>54~sepaTSZk=Z-O%A2*%|6;$3H;|F*>S1R!S~yB=$60wakl$@k z)L>-aaIT`~IfLVQ6cyE!D1jtbUXH#G$Z}-i2UJ1UO=Mk95%?p0<`)!3O44N232QbE4lv(BQ8u13Xe z|C}RLG>bBr<&QK#g~SMyi5S5k<{+U;1xWQPmFA|k5gROdA8k4F%F1K=`>)4wV1QG- z)%c${H(VTqwMj=+p?=q>%&!{KAtn}v~^x7p16_a>A0}*RA9M?Rj7Q9x0~s8DS!&!NaaaLG%FHw zNIN$g3${gWs@wF2`c|aRJSlrHBUD_l5h0_IX`Vroc=j}J^XxMy`3uq%3+A)O*aH(2 zWP`{129Ma%Vg#DMl_sX)Ka-~e`e%bD2N{W6n!9^X4=bZq371An_g}qRE^0YtoF#nF z|JjQ=UHtq|oZd+oSOFA)-KrB;jnV+Z$Lyu75S37$pqC)a@m-J`-iy)|TsA%y2QJ4n z{LUYduLDE8l2Yfan8^;l5OSJ&znhW+E%w?TyXW-kB0l7p9W-AY4xa81mJA|CFP4{W zd&hJ6&%X0b)cG`StYU6xj}m>y9NjP%(f0iU(Q)<@^KH8*KdGTFsi9OZOP?Y6F0!6I zwv&l@xHX%s}k`Lxuk9M8#Y`(kJwW`tU7YF0OVFK!LwJl z1h4w+HU@etN|v=8QYx4r*!RkGuT8gX)n%d`z%@C3%V`I?I!JsjI%Iyp34QZEO71{D z963gP>9b{~lnewyH;kjYR)On{(3Zpu5bY}sUtuq|KT4#&xxVx2l2hSkrk6|ZaQUT86;PsCP#X7VL4UKhcJq#Zq=e$4`j5%N@p~9xE4>ftpHhL5 z*wP~Tv0QZ#fMh0^8*$>k5H4WmqQSXgU0-X10d7h66V%kt7*x5kOX3RP)UOE zP05%J>$Q}?@R8J50$emQDGdu5gZ7DCam$9(hJouC5yg+|1sh+V)~d|ae>MA9c5FOFFFWP!hzs2C`dEi%vJZd_e&c>uxUiL($qf>j#KRa!MqkFDj1lk@i zwT&5!LM?hZFP|8_dl7=L-m+Gjv&L3hv%jeHDeLw1l6KkmO*?~i0oD?Q8RO{V7c+$u z!c4M{YaWK(2oDHHTh30BvxBcDH22DavQ|Aww%>ojnp>a>)Zm0WN#jg868#xi<`KaZhWt++ChxBBMfQ;_K~DeZHEyT7D8_yctS3ku)&+*idg6e4}%&y;H2r z)cVJlizhMLk)I30d>vD#q!N6Ciz71qB)?wb#*9oblvPNm8!Eq8kVG=UXD5bv77hb4imOIgeeXu}8MU8s-@!m{U-@JGz|J}F~ zOCCz&T~~9=P=hRHw4Ioj*~q#S|6YDyd`QcC***-#YAM zfC8^%IGsdZ-{t%vV88EbqUB$Q;M!+_KFWpv`fycd#}e;&9qH5W`a*`WAXD-d!B;Fy z8w%WFzC!W3M+R5l**~RRg*ksTe&A);^j)ue3}Ij{uF6R;h9=9qOC;IXsCkB=a4k)J zz3~^+uLJjPt_A!qFKjWN%+h`zO^3=dL8*5qGBU zs}BXhxTU!+Re*EA>}5padZJJ}$ox~o4c$&GueU~hMy5&9lJ})utXao_UW{T54Qe~YD+ z3x=DtzWZ|9*$Xw6z>J}oWS5h)aW#2j_{3___zw%Gb5+pWm z1p2L&0(C&Iw9=S)1IH8Davb`c5!^eiLQeq0bQ-EC>dSxXtRZxpT)%6GUISLymA*S4 z;alc<)=yohzW>KlrB=(X4E;7Ti#dEE`BgBO_4k+x|EWp$XVT*Q*1}OWX|J^K$=#yE z2nml&*U&$nD)ms;mQ}K`TV83p^dVHsT(5u0o&7)WoZm7lgGXsI!|$sH6feD!ci)Iy z3{UUM+wUv)|M65Q>=p`o-_Z*s)mX>8wm_5p8=zACPZ?b{(uL}Gf!L7W^1WkQ!??)B zO87MEpHCI*GzCn>#Cpfy>W^0>^VX5JXB&N8zsSQso+{Rsn)&@VHpJqp1%JFEztUb> zZ69R{c)(Wvc&f78w3Ef73jTZZ{v$~8zvJe;B!!aHeSx@S11>r=w8syXWecUB1^gf3 CfS#QI literal 0 HcmV?d00001 diff --git a/docs/guides/interactions/message-components/images/image4.png b/docs/guides/interactions/message-components/images/image4.png new file mode 100644 index 0000000000000000000000000000000000000000..c54ab791f3f7faea366b4d849e05da7410a43b4c GIT binary patch literal 20983 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 literal 0 HcmV?d00001 diff --git a/docs/guides/interactions/message-components/images/image6.png b/docs/guides/interactions/message-components/images/image6.png new file mode 100644 index 0000000000000000000000000000000000000000..1536096d088c4502fbad8d21bfbcd6cb776af97e GIT binary patch literal 39425 zcmb5WRa6|!^FK^*cNVwc?(PsE5S-xd2`&K^x5eEFt^tC(EzSbLgIjQST^#;A-{19n z@m|cCo<23*HPuypsyK zb5GUqap0wjJ*BDOr+u8V#^>LB8j>yXa6gA?`R8?TiCEdJO|Xls`<;)+SneFSXk$ww zQ-iR>=?LC%|JOp24T}A*Z=hG*lm_(Pa&g9A{EtMMj0}PQ|48Kjf01-3rl2y-G7A|R z;ZL;-_x39z2*he+4DRFnH&|nMk~GJ*nNm?&KSU3u;SUU96UpV}C6TzVps%0rMsZ62 zk^(!cOz;1Aawq^zMSoTN$vIrCk&>R?Z`)*kvC(^Ra|6<@fFw}MVB_FWv$CZB0c{MX zGyKPU9RnIFijShNk~cP%v5Nf$^|&QBwTK9*24IyH5Y0L9rbvqm1OoG0TXl6O?D=Kr zlaWV%jsaYhb$aFtuo8=GQ()a)6c5btIlaD6*ECBnn-UPVH`^jHs&TIn<3bn9YeQ;A zgJRlGxmJmCguAv zV^I0@;|DJ@Gqdykg_-?&7x{VvH6I@V7Z;bahX)`JgK;MblP^Bgh>r1Rsq~T(!4VBU z=cA$-azdeXJ}v|;r{I`@Fdf`ni7I~43LP!hDBoE9W2A>SOPQKTW2Rkum+FW4F5QH) z{GNHVlYT&r>^9PKb~f1#0X`KC3)z(5WiCZ~#^zq?NPnw~|VASri#&>FXT)0ExHrxF7Vs- z%NkJGz~{%yF6aH1%@n(^1rNC5TXVL!IaIAQ;x&`GexVurEV=66zaz{zMcR6394Ki4 z$%3ix3wtPh)IZ-3G)-2>3ei?p#+bF`3l0ue(>F#5F`nET-5?}^b>hcB#4}7)v2U|2 zFd=o4+m)e7ewg0lT?6ZiDWXL4YuzB>l(~1H<8N{ zT0h0gI+Uf&LSJU8wLD^!xC8qAiSDMrm64e>VQxv=qvV#C8~8f{?gCKf zkQE$#0k0$O%^J1yZ&uT%iKwVD_!RW)sO62<1mdHDN;bmWQNGrv!XF!!&1)!A53-U4 z6@lO`xr_zxf4g*6bAMH@MAy_KPEsdb#Ii2o$+rDM&6TB&CkiuH5VHAIGiqdb)1yXaeKuf{Ik9j} z0G;5k0^_j&Kr4}ED*raT@Rt%}k-}+Q(g#gb?KVj*Jx0-?k2>{ML%jz_C|a^o(cir% zB?Ywz(RKyey`|K3AoDrHPzY`Fsc!SzNG24=#_VlyB=jL!PcQr;o%VzhrBeARyk@Ap z9+}T9L>)&6_o$u~`pD>vCrt)7S9{CpKP^c^0fvQz1(EQGq1g%%6DDNkL>^tag2FO7aA@kT#so4thJ1dy;PNmF3{JrZd-hVP zEpkr_vj8E*de_8cE!5<7wV3!jz#i&#x>%r<0tKT`JCXziTd4f>DR5(u5%8DfJJ(U1 z#K!AGT|)YWJHGTeAUa}D%P=Sv!G!``Yz^0V7!F!infR!QYE~jjkJ9$1rJ)uFzFYw- z#|a)4*HLbwb+-(a6tNrvLKHBez93rl1??Z{4v(m|hQ>bimH$>l{`OGhDCfS2ZRUUM zzVHN+Hs?k@W+(9vsTF;qDp+IrM0CF`CkIIS(Y47b^nHNIp#qa4qOhPr_p@f*MhXXf z>u+R0>*_P;0bJQ6RX0rOhxWTKT*h&#&fO>f+oIvu8)fV?E?cm=D3Bg4vX|9aTe`Xe zAZ@x?MjBd6&&OA5B^r8r0RuS{gH@lgfw2wV(%sNNnL)2!E5kUPq^O%jVL=K|PQ~e8 z5(g(E488Vw1KUu;$L*HG`@~8AK=tyd`7Z#A*-QD}HpiOqZ;9lVO)1Q$DW$pf`9#aj{ZjU2;FrtQ+ znSu+Na;?Qb^G6!;#bXdYmEa%!z++`b`SF)EqOP`B$QE?hjA+&=`i=Nsi8C{&jImYc zmN$@1->MLI8nNdt+WVUdQGwa$6`Y++er0)>vawC*m)|&!;TXnThq#(N+!*MffEC^1XW z+?^y>MOV|PdgE)lBgucJmNB*m(%58k+OHAamyq`?kw{Kp9*u@)UG}%TFZu@8Y{O2F zNx*-f1;Q_ww1p|}FX$k1FQbKTX!uHHk4UFVLxP7S3$#aAtO$KoebHJ@G^ZL8dSpU> zQDJ;Qk_hz~R4-^&-X}yU9g(IsOhNz2J{y7X`i!#bs)Fjb1(cleftS(Dpa%`iAA3v+ ze}F^#jOa;O7R>`9sm$CEEMTqnVp49B1M?>=w0}pPKv}U>mF?!LRkTE2eJfW(Y&pSm z9v8!qec!VAyD%w$*}uPFw>sgi^2AFgXEDzr@_&Qd&;U|gJ=(VJmG)h)8f%Ar-F(pg znT;^b34p!UC1SH4eMB*vFFE*#rsXcpMsC7^rQ%C$EN9#?WQW*9h$XeA#sX%ixWBi9 zO56yo>Ma40w?{9W%Xgam{p6+gDN)w9*XvK;W*Z%h@rGJh78a0?|N6k!?la>!AD{tC zUXjZag@bUV$-?^=YMJm+fe-gm$D1e&si+zrfsb^X1<~DM%gg$}_Ku}VKtPVETt0re_-uuc9pnHYS#k2q`c1Wbz0WQ z_$90f=RkI?cq?(tBeEz=3Y#3&SL@Nfs-$#ek!_zhC!^mNZ8G))^)T7gbO$-4BfWW_V^cH!{%t@0E4%(z3_@#& zvU2CuBlG41pxM#bV5mQ9cB%(jqP-aITU&p4Vr06449M-jd^vKv5^3gegD`=xw*<+A zYf;R`7qAqqhOmSeGD9gjPcQ7MFQa#^NO<2l0s6TUGzUDEPw{5vrBBAyH2d4V?-Pc{ z?tDpy_Tv%Y@3RB2)2SE7jRfr4MHl>pU+DymravvI>*&XariQ1>sr!Gg$`|W0JX9h; zO)FRD*9vX#a@FN<3zi+i-#W%vNuZ~U2=$Z*v(c6aBoIIkjbB_N&Yy!>lW}>v5~&4$ z&xk^9qj1GQvqhGNG0-(Ju=SBQMyk`<4A z1I%m69gxZUV&*;5Gb9v$leYxSoEpna2eNRNzED`bFc@;7Ggm|p$g|4SQw?TOKe$~d zIpW!N-t!%u2x$=@7gVnaq=d3?G)stqmL;r|>#)~iCeEa1e!Jo9s!$*Or%8e{wMsN4;_-GyfLdHm3j^ zJ6Ql|z5#{;S8Ii=zeNW`ZAye<7L& zntO(sDDIcCF1C{{lY+su=Wlc72MyO%6g4PYW;1UW>B?}F`@qwb^~4(N=3A`-y~Kr& zS0wfIuiK#yr<+eD>Q=LiU+esKGTow5-}pfOZ^Ek_6uA4#7y2UpxN;#rFh|ccp}!0$ zNOGbZK>F?Nf!}oT6$|#N8&c*V2iN^s=_m5>ZaxsYcOljZ*_&?r&7auK|7K=UGti`2 z#pp@=X~6e(sn6q|b^!Le21Rd&g@#gdapAxrqML4x6E;{+;yS8Y?Y`M*70r7aK@BHJ z^rX$GJtCw9&GPv|YQAPnJjGo$D9qU?J5N}unyzd#>CLNjU6bp@JAcQ42CVTegAjO& z1#ex`QTpCcDscMmDf!SKN3lto#Op4)p1=8+$y?y+^nQAxLIJGR@85?ZNN8tkc>LQ>7ubxbm zGcJ71ho+&?;TBnB>TdWPQF{}yi3!`w#42lL9R?2yPiMrU5?M|98nfe>Qmn15EfCuF zmGzoTI3`L<@sE34F!uDsddAW zmY8SdN3xC-N)RhJFYp*{Hd)nBM+NJK(w`X9^5u}=2jW7*Ijf}y20AVzle#(S6XJVL zNad;W5ARvRRTHqjhIwx$Q8qorf0U<)7DBUFYLI0Ph-trcTurk?6PJ(64Hu^+9v$*o zkz+Is2LTT4@qVG1R8?gUOPVe~5-{vGK!JXA5E+}oZ;ND`AQ+12AFt}1<*T4BtJs%8VA*y$ zbYt{_8-VqbDSNg@)m80?S(o^x&+SOhdAlaWq^}6PuDeN#=JR|-?%PRk6Faq^@W#0j z6dx`Y60Kbp)Nw-hS>IxEp8=@5)ZJNlztpFI3Eqo0VTsSnF(9YlVE>Fv9XD<^iMwkP zqBvl3u0_yHTKcAOQO~^7Tz{?K_xkdLMmRM-JdEx5I*}#s-oHY%{vsMhHqeclZM(`R^1JY2u%+cyNIG{ zgFoU;b~Y05Ph&J8l(1`1_iH7i$70G}x>EVM$5Ji-?RS-RP;9Eqq%^4s1D0(cap_5$ zN~m?2>zK5IzDxwZyZUJIGa_Mcbow||>8kzygHPq?q1=~!ybB9&kxL=DK z`1^vSQ`M2swtsmVn8qmK6_`i8RK{P{?fj2xA$umFPO|?pp?{L!ovED)Uea9wfX3li zh8BUFNnP=Tj%yoj=r)P`(gECmXr3RRT-`awoq)0GjW-zyu1Pl;3~@?dSi2;V>hw&Q zGO6lp_~eB_f+g4#RM(98REhq~s!hO>r89!5eTKNwED9UydNnmT`c1n{+UK(NbgNhN zN8Qz>xHGtt&z`u#@Por3^?_J$KKnTS#QYABje?_PX^9|r-ybjm*qsz8|Chgjh&^)unZN@xPq|X z_C4^MxY&+AhalyhA>lFf%f{nYIxS>JHMoCO6bRg{MWX9TC?(zXxomd{A3CUV`YSnw82BHE3R+ad`2QsOkGXdm z%(KkA9~+gIAz3=Syvu53MsOR&P|)-r0^D+q45ua{({E)`A=PBv>(=j zE>B>H7*$TmjFiO{uj318Z6rbkT(vH0_b4B2pa;uq=S`f)-%%Yv*seKkzk|ldS#X0A zHFecU=~WJiOCIDC0ycfVrW;|GKGzS>Di3DhxNx5MA&_E4;gK(LRDs3lIJdmYX6v>V zn~D}nKE7=gZ4tfWkH@`QDE2B7xyZ4dAG-VoBQ(9`U7(Z0iZ7HTN23s?g&xWUi^&*H zmmODI7uSB+)jRf!d-)Ddfkr^MNlr*ArO2z*r8ZxxC;!uzR*uH)Y97mY4I9oOjQ&1w7mFa zY6-qCHYt$kiWKYcFnh9#9zf|d6E}XeCxxDPQC18vb(a6D<=2aCS?JiJak<}+C0rGl za9rwD(S6b3cS_|sGdPRsuD4qA*9a}|YF=W=b@X=}l?s_lb{Jjk$n@KPUva@O!d0XI+c*^En%et;#imYUvTwqOAS{7@19>TOq=t;^Vy zBQPDk$Zxnrg(qLb#G)Zy-V66OWnuFZKJr>C1H$kmyxF$SjN`y>)-Q2X3zWrpJ-5KK z^&`;ru0eINPjtvTyj&LX<=g;cGKxoRb^}(j_hkM7<(?7v7;^UfKTu@S_?55){n*+py-AToVpyVdo(F=Kl^|T#4 zxTO-oE&Sm4rqTOG#?_lr!pmM8jxC%O!z};nx}zq6ONhWq?aS!h<-EyxU!$puagjfY zE_6!Y%xK+yB}{DH7o==&aHoWVO<0RZ7Ek9ZV!xzpf4|W*hwKU1Z?af&J2#s_UTHU^ z*+ZH1IaXy`fr1tuCgl5$pZAK~b)Q!LeDmva-bm@Fg}QfecU^zX?Xm%w-;W&zSnlS9 z6BV$2_>4a?1SO<&z!xRHdv+)1_j_o%c*ZjJffu;N+m8g*cfBJ2sxw+{?ZnE>;g~oj zE9roZ#M9ChQ%AJQCH7g8s44h>OSH7D8U+dc1bO43R%QrNwLI6xYDc`2QR;?4;?xe_k zu(lrWg5O+-7;uzsZIU+Th!=jdy{t*Em%B!f-m8y0A-ub=FraRSF{c~I*z z9&dd348D~G(>Zd`*VhQP@X$t>o1LCLoFJinL4XKZr_}a0q>;zQ4nj%0_%hcp?5)Z> zE@voQ1T{x~rF?91$;K$BYu@$8$!@&3bhSA5Fi5$uIM2!wCnSb=yO2C(+z2Xc$ zYe#8TOKyc-`1f+o9S)$drRLPF;aH&(ar4NnoZn@9EmbUlit-bWO=+tVkPQ7pvV4>AUE4EM29pDfRaxhkEC23&r zHk*}Xdkp`+QK*fq=$lA#Eci8>n z<5(=rRlI)?->8j6iSsXO(cG>8KwnCe;O(9hm)9D3hQu|d=%vMn4T5+&tO@))3^MUn z(yRqB`;`e={uq-OPfhenWLETv@1i&#DJrxlkx7!RD zOlJWG2FBxm7aaVcfNrW7iyhl%7j2@HCMKW-glx<3< zwaLb_u{sF(yl1tuV*Cm#{_+UpafKlM3P&H0bBA+I$#{d-c#7t@v^~mYI12qcZ&UYe z&zv<=fV9O)DI}NM!LcL={nSU;LF|@>iunKM__2`mtRZY-NbxX zr19ti*t0wpG>bnVl-_NB@@D^ix5;QFl_=;_`xm(G;4ICA8cs8bMZqE?|VTp|H0cFV}fXwxk{ z*Xk`6h(aBAGVN5!zGY(#)z0Hv@hn83aKu$ozUrCI@=X*p#0WK0mI!=GOX&P5Pi@ilI?^M)P})Hz>W`rVILtn}8SC3K)XSoNWMP!YWGn@iEVjpAhl ztg|foYG?ENQHNdsnhY)iZvPw1Jwjj&JQ)&7LjjvJY|^_NdDe&r@sY+aH}@kTZ5Spx zSXArRd3@i&Afgy~O*a*w8^d+_3kY8i=l zT~;$pI&Szi>^2`3{JVdsUrO;P9>FxVATU9+8G|ib+uW;mScMAbv{MY7V|spF9dq!m zU{I38-{V*$a8`1Np0w-y>3lS!bGFUbuqJ)r3=*I~bxO)EmQ47HmorsWV5>M(b|Dk0fL;9IpaY z#K-VPN4A(gQ@%Z{22J0MBFku`xPa~&Wqu_`pJcC;k(i4O=M$Ke*bQAYRk^;Ce zByZI5mLNQn0sjtH|GKI9n6o1Xw3s~qM;dMt-6^scn6>pzj1>uk@N^3E8rcjV1hgXT z;rQ?g7u{x0o9nLo2b>rjk0e4^gIWFgt&2ek(`^D;A@OJMj{ehjn6eK5Dk33x`9vZTA#x zTEN0SPZ)O6e}8CWfVX~`y=N_-Pa?zs-QLgh$IXNZ5KoHKPdA0XOqfrI4@MON`;xr< zQwSaUwI!WmbXC_r<~=geXg}R)sA-AB`xQ`BT$v_IpE!oc#r0Yy6hMM-;^v96sljXu z8ocguW<8;!rT#uk1#dW={XJY@^YOl~MpXix0)SCfNAytAyev@=rd%qctRNmWwsvv% z{h4{5icu{jv(TIf-5Xk!AN+{wCx=445Ke(&|6JHA7I28U($dzQ4lAH?IaG{e%*f=> zL%0seFDnc33sBtn_`|fmmaghxWe9~r-$s`X*OKtS`NW=_7MDM-1g>JPnf*PBF>fO3 z)?d;j>8ryTR{3)8cnswa`zJ`piWBc+9DsMMebwcvI9q%+w1;Kfizm^D8ZDmb@rdf4 ztfm6Teb=NV$N&68P8VIGGtl7747M(-X*e6bnxF20d%n%%`DpS9%F z!TyCpqDB0veucmYci`ViRD7L$+%%) zHW0RO`?*f+AydQKOU8m(Rw|Onq*8cir&e<3kZm@Ysnd7Umi?2phg)YdWP0^v*e>eE z9Z_-@5$jDn;-p_>q2Uc>ogI*Jp-VVRC|333THupIuU_^j zt4-b~71a2ymkrIVFgIDYER`(XXctEbtOoP-ro8x%LuIm-ZxPL^BpZglp~;xieqW~u zvwJr~Y}Bd!CoH8gNG;fG*6rwl@b@dPopt*_p;Vggh}1EAb01JAuwz+3dib_tB`9{? z@wWhbl%3VOhHVo;!;lxX@G3%Ts@${ZJBAwr7?5l4wXglip~K*t{>M@~Ch9IYCU#aJ z;{p-~J4ZedDGy4?qtDZa+XHd`khl`0RLn# zxn-jF+2;+!=j0o7e&i5dO;6X<*E{y7{9nI%x@Fp>ij5+#rC2n>3iCdxfjye5O?OY` z(^=10`8L;E*FxO`t4}pO=8RM3SOHMg^5-h=#1U!BI# zLYau75`sq>`%RRq@jjp8?T)is&OprAr<7u{y1LgW;ID;21&_Q}f*-V(L;TmU7xMmv{dY-*6{1M)0ME~iPGYZRjY!f0C53M_nNDZ-`)u&;Dp zg#o8~dufJT*gNnaf5nVG?Oz(iEWtWk`BUFGzFwGhdx-@66gwjE`#VjoQ6=hfviHJq;jo*oCj+l%3{!MQIn5Ioz^f^YtWKug38cDY4W?gX zcwj}fSa$L2PCD#jLO2Y>8bb38;?iso2m&C&w7&$CSqf z`bMVP8gZcc`uYc7^XHY@+WXX*r7W$#p zJxq67uXN3+Sb5xSve!1Rf0cC`*f8c!>NNiSuB_TUv*}HExg`k{YH4P-$9METFdicq z5)N6%{VftT`Louu8-*zyzG>pnQAnSs&J@N5Bl~m>i>YS5{z%PWG8lC|S7WYzaPDk9 zotuiJV4~#nQVS)+gyAP+1*=hK8#Y<9IuzqB)|7j1X%l_)O~XX(>egK2!mmtb-xK=8 z1f|Px@DM4XGO~w}R8Ya;&YVy5ySD-Ky23^xqq#%e&NC?J?rn@^b5vAiSl}i3j&kT< zQ`4I691=O{VfRu46NCv82_O>m<}?-Pmx1u|F_lPQF`8Vda?zz0z9h9Lp9mprptW$q zba3yVEN6XQhpk5nan1%3+7t9kr*1S2llw{5l)1=~a9vK;FL9o4Xfz-kF8T zO+Ac~50nOcdtxj40#EvSN#C_pOY+4!z7M`jH>hfF%x&Ik3hD!ltg<_`JKqjrpr@&<`*Z0U<*?#HUOTLv<^wu@g{$$8%=5yv zq;@?mJ+4hlPsHHpycXhrvBKGlQvm=-{jZDeO_8#o%QL#}lfJAz2j9W&qcE*?UJryG z(dVaLvlq6qAoISkCVMd~)5s~qcJhGr+`;CW-V2|3iy4Ulzsr;8#l}-*(R$7$k6<|l zzFC1BZx`j;A42Gm(6T@Q>Bn#OCdi6xeIa6I%v&=b{JiLHTmwL%R}UJDVjr=|r+xnz z79hq6tY6-J`VHbQjIWX?$%#tR$N(4O?5alxKR0jbBh6cEDuZml0b_M4YS;BB{O~w6 zz!x>*Z^c#gWB!7ZuWWNR+q^!$!X{Y2FzOMV8T{O06?@81Z@67Z^Kz|<8FkDHsjcXT zpoPjbd@UIQd_;+4ztbXFWOr#GJ;?B`{Z@GcFRABsW!!1vi|*zjJLHDT{{+o2Y7AB^ zu5_MyQ8nr^lGU;f*J<4#ta23*x)@CT!h12ttZr=4Ga*w_R>dR5oQfP2`;z|Bgi*CL z@_JnV@OS8gkF2BHs z&9Irp`@4Ttj}U^5IjtHC8$h&?{SueG5#E-Jp4=m>YOMpZ*P-j$Ggh5WngFb2VH^&dgkik&)%R>KswYL*H!#Ch5h0H!H z$*7AnFUnW&ODt4F)v?HZUR0j(f$x^9%I$j7%1#-y#qfe)yD+~{dXA`#EA%uuz(vA; zU&q0V!vCfg!Sj>v{$C+yYx_vuv80d(IeU2Tu>VcFV%;}um_BLV`;!VoGLh1dC0lE* zSU=MG1nb1bfYjz^{kgfF?SnW5NS#R*40;|B5=Y4gt5VNxXM@dRN;E+;l37c~p~={E z#P6y$X%45ZlNfPBpbxofBqJ_I;U4Uz)Z%&MBMEKp0oS{-`q(BM%f_lo)0P)nKgyr0 z%8cYCj~lR6Cb(KN1A3<9L9GRA_6 z19Ku_6gQTwPdn%%b^NPu&!|l>Ajq#ARcxlp*#i-uo9VaR1F`9NlY@M7jhvrDqM#h| zp_gK-x83F*L6~#AVzzif*oYl=BQo_)diAIlyrZ#Lz!MWi38I`(@4611sCcSIRH95{ zpI*L+zs^{nKEjwa3N5Zb#F+t|{3P;ui=>s=s@2Py(N{EkV|Ri=6)iMc?xW#EKjcpo zlf^3bhUfR8iZvhx2-^p7c=fSIUOmcfh^Z1s`m>I^Q0@1|EiFkON<$w_xy!*F;WZKZZ$rX~p6wR|Kx+~xU3Hf7PoF8#gaw)BTkZMo44L|#k= zmB*T)t=Fgs`!SDPR5wfvX-p8P5gx^ihGy%_1f_(ciH!|K6;tQ3E?y>-S_V}kOHh;r z=`)2#g*F8jA|B|iWeLqAQRJf9|1&~NR$peWzFe4!J=XjmzHdlpglVsGlnaI=6BK+v zMJMZVGO(0&X`^5|^agCQN;{BXIX4$7=9_vsn!}<+bEAyWvp~t2d+TPJrdl&_h|M~} zM=z60GSYTFNMOBV4edQ1KVfoj^y@mq=DFhjn_{5u{Y#i~NY1yH#6;zoass*fMGGuT zxC|-<-HpRX5cx~p)6A3mWKxhf7Xp($C+HOSuW4#=8kE>)BKigMa*~V_;U7oANZ9yZ zYcercu-2jmoll$2YrYHZee`01_oY!NKK&P8a{UoD8;5wSk2?c?ZceV)X14bo3}MXK z!9_=%kt|B;H*MZ9RV0XFrb`&D%n%(xn?NPb&Q9Uf-M#m<`{0U73KDmErVVYr*|DSg zFRyXP_AVJQh~5YEv(lgn7M~u=ebNNYDJpy=)Gybj2%?5o$QT}G+qfxOL@rxOY&!s! zU-WH#L!&4|Gruq9hkgRjlSNa~45;dA>AYlf=2)xGr~k+Cz+ZQv23@x2L79L1=QWb{ zAeLfQAfK*Rl^z|568IrWAdSDF)B{+5#C?=I;0Ilf&= zxp>hHh$Ijfe^xx!;3Z-ebg3qxeq~ltxsj9UBv?OVmG=_rey;|{(807bj0YqBm;XsH zp5N`6&u1Z|bjRq1_$bAonbR2Q3R-MNS~WVg?DyDnFTs*L)qFA!(;6A1)A(GaEm)yj zYtdV!QY!zAk`6F_8J<;v>lE-abQRYE$wHr}^MXWwe&_$vOquNKnar*i8t|ZaydmL{ zW+o;yqcakrw0}e(7)pi${;Fcb_!~4nXLp^Re_9^|Vo_C4nZ^J-BP_R{6)N82;sH?N zT7p6eCy6p6LN(II|S#&jgtqn z80lDx+u9Uxj`m|DDTRVxv?5Nn5kvdtZ~h>?mbD4ZK$VOUhAA%}n)u{+XGvY?HN&Ut z5iNI!)O4+Cb9AW^>w4%#>-wkT`~v$b#kMkN+~gMndy$h)2iNenijU(+q`2xLT-kc6 z`(s-?&wF3Ch@)D2Kd7Co#&2)Y{$~~HH%H^^Rk&!y0JJ{894_+=5$TYe&EML{d^X^; zSb5&a#=4r!Pzjkby6ro(s_MT*F$j&zBs{iu<7Iz;<_nO7j`~>wGSm$RvsCnoEtsm> zT1c^c$ZM=bzmZfWAeopFJV0Jw;!TKG^VYKEyAxms%+F6xFQ99$dc- zIvKBWsMxJ?j4t^fP7k#%B{5uXqN6mk`l045Lyjyf@B4K(hSF>OTU4?aXI2wifkJz9 zkdMRvJox!^e%8T}nk)x){yWZ*eBZ}lS%nwI?3;HQ&4(XY=TR2t}`%jk=*mlM&tgR41YuB2o_tCCHta^OWn@r&WWhnH)3-pQ`k!OZZak{@7h+)`&M>eMn`OL9Py!Aw<{kD z@y3&|x$k)L=$O>B?m`~@3yK%rE%5Cc9eiVqxb{|0)DbsJ-Jllcog9O}?O$hrV4yV7 zmsj~caCRO%QtJ7Ozp4p3vgY@2|7wU*>0g&Yz^YQ8&WpTxguAm#x;Ya-0=oi40e@Gi zQXRT|3X&b23WK03+He8oCgD{BIwGDi0-of~%_^tgGo*f5ajSHRvDc;`P6oEYAoKW`NWx&LfJ{UZWZFoiuEQLc#6C@Z zZYX@^UBQ>~=LyPUZ&$RW+0p<5IgyX;lg<85i*&vK@NuCj_pLKZVZvqqg7ZBv8kJ2y zFf%WrpxGewEGZ!7OvKa#F!$&fe9=v-|LD@n@P3#Fb%f;NaQ@>CekQfyhW33o_JaOU zw+Al=B+tT!o>KT1?^}d(*tZ&{d1`JZoVrXz-!>NI>|r|7%hMuiktgccYf751G2%G! zk&s32u`_SyUbk9HN2(|&IL^o>W^3R>Mq@rl!mGr|Feyl{VBeVxz zpzaDBp+niJ=r4_c6fg{rbVWjv7ToE9Y-_+0D`@TvQV#3#q2O)q{31(shRfajW7q>} zqN{Mr+~cgh*i7C1U}&q$9<7r3ib_OMfhZpwow600+}6qF1+zr(_!Ei9>(Xhuru~nL zACHw+HqMt;=1fJQ3u<5GKa=w20+! zOi6~gWGuL$jkUV&ZX3!JF{qGDXs{USaI3Qc^p3r_Ut1wGpT}RZV-`&cN?ZC8+gkpm zZcAmwXYRf|_N8kxzs`185BbY@S>L1bPeFHWj@6i#!SAe#LM+ZubGEfNZbC1F=Z`H5a=Cs#ePo&A z_UEN=$fEVO@TD|h3yr=cKrNV~vrRU2)2j4lyK1t$4Hw20Q;s_#NQ~08?Y=^3=o3MKAA&7d9I)B5^8fKl9BIhG#G4UqGqHC$VtXOR!4bS8+ z8U#yp2c}*lNwKJ?-`8>0TjK1sHNL5YV&p}5%?y6D{i6x=+Wmok=@~xX;PN2VdhKMN zlPn$7_oH~12#5F35nOMLQ#e4^ii0H{PI#8tpS!YHU>tNYPy+m+HM(0}Hb$y`S;XaP zeVjQisq|9}39oQ9ky@oKNz}>&otTdVPyfWg5!ZVBJ#3;DUSwvl;IbZ}rNzXSgE#AE zFgpTSuKrnjAD0A!(tlJx6!7=Ym%7JtA$wH;^YghG4vV=h-P*4)jn{hi?$NcjFCF&_ z=Y*zxfnCT~c!UnJA`jxC0@0^AG5;3tlLZs8rH5;@Ti^`bmk{u6-dN*45W3kG%w*-y z=y4Y30b0f{hO!ktl+9$-`Kc1~`x^z;yY`Iqkvom!BX+#GqhrB)$jn4li{e|I%Mh@* zIj#6`k_!`v986*}aK?@obf~Nhc8lgB$W(MWY8Js#|4|*P=FeR8Erd;IyOes~E6@Ty zPpWPvO4!TN`(ld;H#0qB>b1c(^s&?(JH>A#+8Fmex=(H=`Yf1!i6fy&TMI9bMKd~MIXW=S{y?Ihk@ z>4&Xay%KmgFA!VDm%Og7^5%QY zK69VvxaL~8I-Slp((h0BK2nEx|(2*h5} z`Y8S6QtM(y&+>o(IbIpNdBQGBF04JD)=xkKfqTw1{CxOXUlUPOch^6=+i--+3FpV%5N#{G(L#|X0@4|Xg5e|LbGDVFT6d&cv@DZ?YG*N4MztCe zjp4?$?!N`hZ|*nOkkcN4QkH@^(*pJEzHy5JgTw$_ zlc<6YBR+<@&GN}a^SgE^Ahp)7#I#0nr_}nX9o`GdXW9O5n59Mflz>^~8aRW{+hKD^&V;B-m(P+huj)?~k22m_s}d1=73&7JCsxguK6Zn^m`y+il_L=JOka zR6qniR&*m*3~mEGY;N*NvFoqV)PK`Yu{|l#>)5_+{|xkEp@g7uRP{fdcSmEL6VH;_ z3rpQGq4f?*qUQjpR3ahwU95t}qQU1P$qO0VB9n!n&{Z7ereZfv+OLtKfCv$din(^1 zO}Y^;#<{*0hygcpS2Zrt@kzf^gQA#$-FHBjJ@fDn?)EXm^Qg-&Cl^HdLg7Vx{0o&wiV=dh1s8O6bK^h*nPJ=eh{Ar~|jVzSw^ue~YYl>I5k!Gpms zv~&N*1u-X*i!ZM~?w0TGgn9@0eF@Lf?!G!-ghKgo9Pyc>toO51NpUiHjR7ycDi2UM z-@Nj{2%p@(DB^x>0b5~hQ8xj(Rx7g=1_zMiulfSa_9#}DnD^cBwr~iR)N^wH@hkqN z+sP+wzywK6_uu(@Ee&H|+(U*pnm8lb6^+F2H&U}Zb<*K?fboLZE>XH!WQej#PXadK z0XNq6r*zMF6=W;+WnGum+^WHf>Z7YtJnh`Ys9QUoP0!J^P0wSGqD7t$U(OY<_dRm! z4v@fiAI|gUZ0{{ws?wN&Oxk0|X#ctvoX=nEYR`(Q1b?u1Z~Kie*T$aSq2}o-#Ui1N zBu=Fjn;WFFci7mO%N|g%{!q7o2C99oSJ_IYs904T8pQIXQYDERAUz)}>duKPYwri1 zhwdBj)2t{we8YHM{85VZZVn646d3k~N4*Q`TDAd9(RLN}H)IpF+(vlqRi8(Zf)OX> zQW%^t#aJe4ZA1)szg@r%JRBsr)Qflu2nNUC_App$jPA+F`DxMytA&nPI0&>fm$Uq4&||3AR8a@I=Tpg+1-rTcZ>yR-wB9)pVHNBM!O zCYP2-?o@;85BSDLxGN>%_WTT&f9gcbkW`1T7krED&*kubow*f6^4U+*f)4AQzsXO| zV^WG_$0_ES0T1RpFE<;SqRA|o$wtr0eVb^KzdW7-_lJCJUdwEM@J({Krt~d@1FF^Mc~u0AcJh27VU1oeTR}51a=l!c7+&!Q zcyTwY&ctsd^E=h9yR2Z^6vS0kT+Pm_x03D1gD&B2w#! z$9x|$**1bZ?dS6~4LZhlu%GdVTCrXVh4bOOY!EyC6}PVXe~JE1EfH`tam%D{XxPy~ zxDQQ~7SYzwCD5|IposF}_q+_S@ZSGt=S?MJF815>W=V1SqUdU4v&I4SY^*$01U_kIN!$Kuq^ORyV2FrFeYrw9wg4Ry^nKF_V-G9MSZiKDp5(>X(ntsT94F zh6Qx0s>$&iPU8KMg5sQ1GqtM!ovh)2DkNv|a$jO)m*7ExKnm5Y!QRy2Crl5lqJV(m zeED4<+2u#`U}fzji8I(ZuN9|zUHk5wcD2596vymC2om>QU=-GddXJZ1YR#Q!+@<)k z!rC)7|Cz(1RQuMb3Lr-~fHXR~Q@YxmMtnL5wG(q%&?CAXh1VX>gChil8!t7aF8@kh7&TiNSUHoX3q;#rEl zaaBe5pK>4Vmh}G%D8z!5n17tHNy@{6Few%k``}vwY(a6y8N#G$LR(ugG?{JO@+?YW z=mL9(TGM%o5>It0cAfWh%>!a$eXpUT7%SL-gD zD!tvpq)IFPO0**d1%vAj#vOxC4#r)BS$%j3f&Qc}$oqT_giC*mb0)<9>67!;v3$wD z2XZw%oC0cp{*@esV35+PeoFrLZx~i0(IUoo!T&DXPX6D^zyEvxMH$vh5ghMfc;e7? zQxo6Z5*ulrU0`GzFYjQa156{K=L#<9#%%J4TpkVZo2ujr*2j$Q-0MKSE3gBMgOO<} z;|Lm~Km+5`ILVO`+!v=?D!Wg@Zo;sy#wn+#sJD+;kB|Wf|QwO{hGq-y?>I2%2 zd5J^`_91cBd&U%3tVPr`%ekBw&e>R=sni^fiYiq+9kt2#1|NbrE{;ON9JIH7x1d@) zwvy=Rpcpq3iw5FFtDDoqB2-pmV+!POO1Sleg9xeJfgKNLHa;3b&NA=`v*4ltMvU}zz1vQI_Ma6mWOq73!1>2+Q zU)x?dKkp$42{B^>48wxJDTc*#?*-JvZD%TA}g2XCubjPQyJ)E^>C z=j^CHP-`yp&5uoY`vOhy5u80CaGO7uA?6+RiGL;ZIBsrF&5mnSs?3=RN|Z?!Ov+^~ zE$Rgu_&5$K5`S!LdC6%vGcz*iU=Ego4KFM#|4v)OQLgd#e2%NY!G7^wtW2-9an}>~ z)3lvJId+_n4gIlhcn(Df;keX7glHZ0qZBx^a)B8fhL-xT?kM66iXTw4KQ*-#+eeh) zZOgMbqOkX$2$`X#(8RxSsDn({Df!}8 zN1AWo-a^36Em67h+>1R(Kq+T_M1U2Q=y7|Dle~62cHok3+_%o1i;_`ooM43`?v$dsadW2|k%py8CZ=;_+WNA*ato6v zu$y@cG&C*#?I{Y0hkBm;ay-P(9af9Dom({~p?=X>`&fc}N}L9HP*S4Qtvp_2@Z{~gDL4x&58!XiY=h79DKGCoM_Zf?yhNl3#11-qu_#yDn4<%8Zyr*m(kaqGiT4Eq`Fe0ilbPh386%`ST} zkb6n($p)~2cZ~PK^MS`;p(WetdNyFC9hd7Ep;^J-*O4kO+aBs+a`~`R{m0wH`623O zdbdYNme_D!m+9GwAhA(scf$C^BGI)zE_5?egG_bxHjXbl(_rZM*l>4YoPV1Yo7(=l z1Dj||0uAM`74@=LQR+Ka9qfKJFcEqLH9JjMwcbyn2%xLL9;NPLEjUh_e~4EE(H&Ry zw-^KcOLD|qC86=lPMhBckI`92kuvK}<=OFRoC$4|d5|FJU1=7{k8{Mz7b z1x-rVezA(8iEkKAwzx+3Psh$)@)`l>T}Q~+@xcCZ{cug=bI`qFs;2^7<@jYl1M%L{ zt;K2NylCJzj-)7gBy%|q`+?rSaSB89n^DT&wLQT7aq(;cd%*2jmHlw+an^@M){u$_ zDs}Sf8@Zv22mHp-ZEfAJLHZ7Pk|W@Ea4-|w-z)lmt3KpWJg3Tb! z`831#&6^9VrpIQ?nLHWH44z(IoaFC1|DN#VWSZK0u6&xFd#(bSX{w~ZZz~yZ{loqy znEu4;n7w`(-dumPkj^(!JZ~HIJVyQoqrY2*!Oi~dJO5ASz5m|q?SGu=|Kbw-|LKnY z$wzA;IX83z;ugCg3DgE^Gu5x6k#@*INcPO!YHGgtvTG6;i~n3o`sITw)4r<51R^BL zv&P_zcD|)-S`jagn27v!uUFs1G1mMoUZ)xM#lxy(fGPjK_Qj}%gH#yg%U#S}yM{C5 z84Iw}@OAb0a+KtS;2B?P9R?aBk;T?e42_Kg12ZQp@P8Tu!!Ve{@vFYUq&hG2Oe4(> zRsXUw8jfde`eQu&Nx&QLK08_S075|HFk4~;+kYf&UT^9?d$PY{X29F6ok4`r3+u+}%Ln-YQ?W{SL{qf(EwuP-Tc?N`q8=(QZ4 z0LGv0Lfky9BYcJd7UPWOli++jGQ4C0ri~De;2KeLc?RQ~;v zl65-e);;2=kr9Qr@mFeiq6Bw40_0a)OsVvSw^iYADv4C5%tT~yv;3E$kDr8$&w`pmyq>ua-r7V1i)Jt}AW%eEY3x3WB!g}3hQ7oz& z?Sx7gm$ayA6%Xxe_wc6V+Y4(|`FUfZ2RS*@`I4|~s%T8=$kg4}Z*^7ECoRD|R51ma zAJ}zbEwa(Atp@gP8FW3bKY=rfc>I36s)KyzroFi(wonk2V`#pUqI98UCul_8s4hDaNu4@5IWhhleDiPHR2`@FfRWXb)X`Be97+WZZ6>~ z+`JmSohY$6fIrO?kU-!sH-d$;J1OrX_nAi3Aaxp{o04|21Kj-hi>~|8#XiQX>O*Gg zF%nX{@!(^f5q9IJeC~BbZsN^1+6Dtnkwa&Ke*MV%%hsi1r|!px&c%E?q(b;Hle;X* zK3W0$z^BDIsp5>W(%w2s>vXah92&d4+do+@Y3cb);(OWS(~F3bVPO}yw}e$U1to)U zko$Yd@&%a7)%bK0Q?ptMm*Aap6Tt$VlQM&Ji|7|9GX+4 z;us|>E9iaF`B&kE2@9i%tBFQuuMnwMzz@Ro6Dm=8$UI8KCB0K{_4$-LFPg{+9}u1; z`je-ZTiUEvXm}yEeYH-$!$d9;H2}>X%>xnTC=z4uQI-(bu^^w?OLT*SObJ1=Siz9d zMX(148LzIGo?$g2H#fH%_~%jOkRuny;_+|KPm9V$!bzV$Q;S1VlUYRL6EewVFwsbu zc+tn36o^_v)}s@;O-Bsf=c(gSLkO-oZajJ1*zA8hsHwe4{+y-sMeur2yx<+lc)-MH zaR*4D`2!_EX0f~^+b(FawXIOJuJ8Ib08;Su7f*spTPPg_^w(9GVTJjlN1GLEGSoLY z*HG5{yrevKw=FUis1L9c*5ctzm@G-iL1)a8ecQ}Sy_pA8#Kmhf!#-S(jU)W#O#X@Z z5lh65x_T+!weV%eSU8z6fxRh6l`=NaCw?SeA-Ud14yxz=p-8DVOz9XF&Pomg>j5&W zeeD7**iUALhU$;77ew)dxAHeY4p)UYind{LPFU$8Wh~V zuQ#{0((OC%33jet#yd}bA3-R#$+*7ftJJTCOVd={NB@((B58Gu-f)4 zl#q;UXoZK!Vog{MlLi?F2dC5CP*qE76v2Ahl{;Qta`|kABq%)a0{vf?Mr@_$C!Ag`PAfCymXFdN}5!sVZ zfsCCf?c~H3;4;++(dXzWX4k@y-gQkhAOG3Rh_ETmiZgp?I@;r?yHFV^)>D+=N zua^yZPGoMgFeUWjRpf)(obDSeH@UM}jrq}k!3)FhBGh$WvsHE9`z3A)5W|3hj}S8+sHueSL$Z-U2h{Nxb|>-eBrWO{yGG$U_uX8nB($xS6z3fl3@ z>&y!>ehLBQl*l89U&e)>yUR_nFh%P)w#9K=*g!LCE<^W0OAVCkEiD-VQmVI8RFj zgIkiWKypjqPj;ptXnT?85&&-joU4GZx)P& zVX=Mk=O*P8rOOamfcQs2K|!R~CGM}uaC)2+D!=;E)2drT(R{={8$slrI091Ry~?Q% zqj<#evjwy7gKDi8BoP51!_+W(aAy*-o6igUKt3oXug;M0P;@@zfvVHV@|s|u3*#c@ zk@z)v)C6dn6oK)zDmE1S%RHorrG@MBG54NRM)t0RC{33fbf7n| z{bNRRP6rtK&H8Eft(H^+)_4<0+TeCCJw*;M0hbfsusKq@>VS(&k)qa~Vv!yjnRa+? znBdXd__`O5lsf!9i5c-DE^>*=rozm?NpQBsk`s=pUN}0*n!`@F1mf4Uj=km>654l~ zh&XqOkHa+pCiBtwg^P)`Bn}wbp{K@6*PtDW{kv68fdp!94=h+_KQXP0q7V`6?s5SA zJ_!CEvz}L3u9$uSkFjyOv421}T1FNO^ytL@)tZ$0@l8%fiLA9GRe}n>%&VF-f3=vz zP2^IVe5D4d*{;S>8-X52to$A#p%aw8kk9A>m}zAvmWb_znx?aXw+uxMC52<ducJ74Pq9q_8M)6gT>J!sZ4x6N4Uc(3zxOp&+&C z4SPQacB^hr#G;l)ACG1~$L)=)pkG@ngba=A0ERIpyl8gkZx@2ds=G1e-|!~ z6VYhKk!*P>oa?Go#6$Q;UVL=Hkl)x`@?v5EHG_9frAP=fYiZ7Hw@gwusy>1s`?S@$MCPL(EzfFr~Yfh5Wb8}!W`wK4@Q=Ij^2 zL~COKn2re?ttJPB-r+Pyu!V4m5sl-V3{T$L2TJX6(Xu0#UJ*j?mhYPWX!0{BvVK%H zj*OBd144dR2^t$Fd_EzhtU()EvTNo%X>;n>T@r_Oo|Dd2w4OFOeW9wgehHSN)xD!n zMy={MZixOKE@}by`SSx@K(Zw8Q=&B(bLQsV;4O!`V_RT7aJ8wF5r@5*fNP$fB0z(} zVb7fFDY}%i@PRNODroB~Ce_-xbGq9eB~C%mIa^>zGjZFOEyS023&ptP*EpwmuuECU+=`EnDUyC1g6@R);WZy>bf&qXA`V+?zy z@HSZ#)ldsr^o>W9A)}}02~-yq!WzhqLjT&*@mf+ zUESnahpA7j&E4vEk|tGqz-QgwZ^=g3dUTS~{b+OGLnc8BTB;!|5XojtyympzH;BYt zj*JqdzU?;+i=X=yu8Z5!v^pU{->aQ~(<>LJa{Z^x=r&T~7XpSvemmSk19#MLrXpF-GD0|`;$Bo&UTNbPR$kta#Lc4XDqJHEKPvw&|RXKY2o!!zr& z8xo}zy;>cP0PcJKY(rlMs+@{MCHTS6nXxtz$XGJ5%qTY40_{STU>WP6>%bS?NZXHY zm!`+kezeL^4x;bbVpelD#b#aVqMYL+Whofv5n8qsBwA2ce4#1a8<%5CU>zl4et4Se zhOLYPxkF;Zpk{0_zvEbLW%vXa>kpcTUdkokM~tvA9C4&C)v1pqDZT(CoF52X$l@Tx zG(j#(K%ater(Q+VQ#FR%CS+_~2@AjMNiD6rCxXd($vi}#mRF5_-lQPBGb~osdUv8> zdbG0rwx`W+AfRS<=AiwMMAvw(vWdnbiO=g(I36Bm!6rnYcip_uNS@Cj@`g1A+fhpQ z`cK4X6U04|aG2MUuVw^2Q#~9MVVG8Al+_puY8hyfrPdMh`~ zSFFXN&>HuQIOINzj-X1*_;xlq?n&m{F&SKL>_fK128i;+=>dL8n%BX*rAaB*!@#{z5XhA%Uz(y&sBq1*z1kWVgL|J$(CrH)Fs~TJ@P=W+ z#N%D^1`icL{$(o$eITy$bV1AaN`=LZ0z*ApY_rwr=Qm#p>D^;zhXaFIfYdc7A+^8I zh{%ZKnFt|9$Q@~s;S*f2KnP};bP)SMp<;!(jy(gyLz0 z*FO=i!2BxMRKU$|FeQr;|JQ$GIs!SYE1rN%DH)1U8L)#_NWwGV3e;4?1tnIjCnYi*mBi{92?OdsuXgg1^4$$rGo~xeF;LI zHY8MaeUHMH*1CRSGeRSy?<9b}A9BT^hXiKNE9d>=62=cq?T+`vWVw2(&4_wez&E8w z5O?-F{hkwBX7@VySkl83wKQ_eD(byIyx&LG%X7H&-`xC>lU-LMjBOQGa*6z~Z(rMH z54zIQeOPkReYxXtu_gKipu=I!eFSTy!yWIrU`JK6BW4^4-5vQdL zI?2>)F99%%=2__#G(&Qm0WL z+1gEfjQ&_EVlnby4ze3~+r~=|L}$11&^H`Afa)~ zM6h(^*`zxoH6Fszc;N8W&)*-FN!k62DGV)KMJHvkL%IHzh>05*CScEA_T-S}(ZKUg#L+oN>9qyX!p9|Dum)d)KNp@%nU_vss zsRF!_l3ZFLV)o_1rr_NYo&VDN#Pjo{@NW@RzY(p^e@-gpNLg?(o4qY#gWb8gXE9X7 z#7H4e?|OT(qBN-$UY_BD9eI+7!GrD6g*bcls=D+QcY@BQ9>mI*_!oJ6Mn*OR&kb0? z*WSVOcb#uZZe`Qy6Dj2Tf)34|sM_st}O}X?;+nQ3xUN|hdTuV z1j1b;*@l1ofj-zXV|sC0Y%pN~C#zgmLAfuvrl@M*ew+KYWy2=_Xv*jWWa#yNGGDO} z`F3*=3dHPEnk!(%6O)?vJtW{ReqTXZIlQ6Y*p?lJc$8yGB#iFK+G5`{E5$qC(NeunT@0; zi<*~-9*!t}S{rLFC}y)q$C7`~mcNt9*!r8sbvK;y$%gg)%a}z6Gcg7UPL#vSP`g7J zxY&yzZ*-8knGu8Q)CeOIbDDQnk4`=b68PDaq1kEdc zYcDOqd>2Bgy-SXo9p7H^Im`LsEG%qDggVF346c5pDaag%6o9Ri5L$JR5OiwH^7H zzfz134!;YBhoTrYBna!-rI5O@Pb1}}rwSPdS`MFW?6VolhqJt!a-L9*{ToI=0zO^` zmqt6nhEe25ydcxU>CF&VR21N`@8)}pQ$fYQ5HKbVf2&E4dbSGGr{DHTDo)bV(~G)j zQk}`+(&|Lsw7Z2qJlyse7pn|}7Hk@pt~d~4grk+qp)U?>v{Q{I7rz?do$Pe8;PN?h z92p%&C&4;k(z+NBt-hYly6|hYnG21H(H1<~y-2eF2s=(M(^jaUGAfgDEX^1lwRy{* z4q<|n#tJ+h_4#A?@$+Q$w5Nnp62KL+T%f_RyXHPt$^;sdD5fZowM@oSsL%G!s`ICe z@znfFAc0DY70qzEifHs`DFg6%6sNEjsk@2nct9b_e&%C)vX*XJUj2Cr2CmU$I2}$g zihzYq7IGZU`qZD9V&d0t_6VTBD2npD+bTNw(%*7Btx}YN1{j&$?HW%z>-$0o9b2SP z4+J~ATS*(PKLZ(lmeO;*42?JaZfIu9ufAs+)9nN^NqNab=V?2=F6q!==?KC<-J$gl zUv-dP@tIil{KJRbfr?dg3?%2s2)^&woXkG3tl2`iCkc7~P?H1(egW+DN6P#dLwlt| zHqhiEHzoQ!!4D#jPyWqvgT(Tdwf84BI*bGPoKPIo+8Y?08`pm6P;nW7InXO7FLK(^ z;k$1V0Jn!39#C@I5zg z(r2&v@EWo)5PayFZm;N`_;||vMk^$oFJFDsj&81|^JOUPt?vsB#6>`bTelyo42n@! zfm{=W;L+eot-IT~zZL@nCR0+gpAkh~cVIhY`+R8{<69CLb26g*LP^=k=Wy<=6G&d{ z)73O~NiG!ZE+r4^X>E7k!$`TlpNtH$S9cd7z0*!91C{LuCTDHJqCsD9c|{0U1U1+` z`f{FX>+UJBUK6!Abx=(xvEsH1G?t5wG10H*#2Xo%1~8@o5`A3^MZ0_Q&Aun=2TV>< zQg_Dqt$avSqQ(5vJf3D?88i1d+ z*^8b@*M4=xYOLGvYc+c%6O1<${(!EU@j~5Qc9j)UVsjH>&il~_$}0q)){rURI&7VS zK5CM7oZxhN+^Rw{P5_VjJOR7Hw#1fJzj3n!$y%A1ENl%0AFvb#N7fe8Hdhlf=EO&m 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 H+rIxV45D%) literal 0 HcmV?d00001 diff --git a/docs/guides/toc.yml b/docs/guides/toc.yml index a6c38768f..968468416 100644 --- a/docs/guides/toc.yml +++ b/docs/guides/toc.yml @@ -1,26 +1,15 @@ - name: Introduction topicUid: Guides.Introduction -- name: Getting Started +- name: "Working with Guild Events" items: - - name: Installation - topicUid: Guides.GettingStarted.Installation - items: - - name: Nightly Builds - topicUid: Guides.GettingStarted.Installation.Nightlies - - name: Your First Bot - topicUid: Guides.GettingStarted.FirstBot - - name: Terminology - topicUid: Guides.GettingStarted.Terminology -- name: Basic Concepts - items: - - name: Logging Data - topicUid: Guides.Concepts.Logging - - name: Working with Events - topicUid: Guides.Concepts.Events - - name: Managing Connections - topicUid: Guides.Concepts.ManageConnections - - name: Entities - topicUid: Guides.Concepts.Entities + - name: Introduction + topicUid: Guides.GuildEvents.Intro + - name: Creating Events + topicUid: Guides.GuildEvents.Creating + - name: Getting Event Users + topicUid: Guides.GuildEvents.GettingUsers + - name: Modifying Events + topicUid: Guides.GuildEvents.Modifying - name: Working with Commands items: - name: Introduction @@ -35,9 +24,45 @@ topicUid: Guides.Commands.DI - name: Post-execution Handling topicUid: Guides.Commands.PostExecution +- name: Working with Slash Commands + items: + - name: Introduction + topicUid: Guides.SlashCommands.Intro + - name: Creating slash commands + topicUid: Guides.SlashCommands.Creating + - name: Receiving and responding to slash commands + topicUid: Guides.SlashCommands.Receiving + - name: Slash command parameters + topicUid: Guides.SlashCommands.Parameters + - name: Ephemeral responses + topicUid: Guides.SlashCommands.Ephemeral + - name: Sub commands + topicUid: Guides.SlashCommands.SubCommand + - name: Slash command choices + topicUid: Guides.SlashCommands.Choices + - name: Slash commands Bulk Overwrites + topicUid: Guides.SlashCommands.BulkOverwrite +- name: Working with Context commands + items: + - name: Creating Context Commands + topicUid: Guides.ContextCommands.Creating + - name: Receiving Context Commands + topicUid: Guides.ContextCommands.Reveiving +- name: Working with Message Components + items: + - name: Getting started + topicUid: Guides.MessageComponents.GettingStarted + - name: Responding to Components + topicUid: Guides.MessageComponents.Responding + - name: Buttons in depth + topicUid: Guides.MessageComponents.Buttons + - name: Select menus + topicUid: Guides.MessageComponents.SelectMenus + - name: Advanced Concepts + topicUid: Guides.MessageComponents.Advanced - name: Emoji topicUid: Guides.Emoji - name: Voice topicUid: Guides.Voice.SendingVoice - name: Deployment - topicUid: Guides.Deployment \ No newline at end of file + topicUid: Guides.Deployment diff --git a/samples/02_commands_framework/02_commands_framework.csproj b/samples/02_commands_framework/02_commands_framework.csproj index 151e546a2..83a62f8d7 100644 --- a/samples/02_commands_framework/02_commands_framework.csproj +++ b/samples/02_commands_framework/02_commands_framework.csproj @@ -6,7 +6,7 @@ - + diff --git a/samples/02_commands_framework/Modules/PublicModule.cs b/samples/02_commands_framework/Modules/PublicModule.cs index b9263649f..18423f609 100644 --- a/samples/02_commands_framework/Modules/PublicModule.cs +++ b/samples/02_commands_framework/Modules/PublicModule.cs @@ -31,7 +31,7 @@ public async Task CatAsync() [Command("userinfo")] public async Task UserInfoAsync(IUser user = null) { - user = user ?? Context.User; + user ??= Context.User; await ReplyAsync(user.ToString()); } diff --git a/samples/02_commands_framework/Program.cs b/samples/02_commands_framework/Program.cs index 67cb87764..8a2f37dce 100644 --- a/samples/02_commands_framework/Program.cs +++ b/samples/02_commands_framework/Program.cs @@ -39,7 +39,7 @@ public async Task MainAsync() services.GetRequiredService().Log += LogAsync; // Tokens should be considered secret data and never hard-coded. - // We can read from the environment variable to avoid hardcoding. + // We can read from the environment variable to avoid hard coding. await client.LoginAsync(TokenType.Bot, Environment.GetEnvironmentVariable("token")); await client.StartAsync(); diff --git a/samples/03_sharded_client/03_sharded_client.csproj b/samples/03_sharded_client/03_sharded_client.csproj index 24f9942f9..91cacef64 100644 --- a/samples/03_sharded_client/03_sharded_client.csproj +++ b/samples/03_sharded_client/03_sharded_client.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/03_sharded_client/Services/CommandHandlingService.cs b/samples/03_sharded_client/Services/CommandHandlingService.cs index 1230cbcff..adc91b12c 100644 --- a/samples/03_sharded_client/Services/CommandHandlingService.cs +++ b/samples/03_sharded_client/Services/CommandHandlingService.cs @@ -54,7 +54,7 @@ public async Task CommandExecutedAsync(Optional command, ICommandCo if (!command.IsSpecified) return; - // the command was succesful, we don't care about this result, unless we want to log that a command succeeded. + // the command was successful, we don't care about this result, unless we want to log that a command succeeded. if (result.IsSuccess) return; diff --git a/samples/idn/Inspector.cs b/samples/idn/Inspector.cs index 3806e0e79..1544c8d07 100644 --- a/samples/idn/Inspector.cs +++ b/samples/idn/Inspector.cs @@ -3,7 +3,7 @@ using System.Reflection; using System.Text; -namespace idn +namespace Idn { public static class Inspector { diff --git a/samples/idn/Program.cs b/samples/idn/Program.cs index ffd8fd1af..abc315a2d 100644 --- a/samples/idn/Program.cs +++ b/samples/idn/Program.cs @@ -13,7 +13,7 @@ using System.Text; using System.Diagnostics; -namespace idn +namespace Idn { public class Program { diff --git a/samples/idn/idn.csproj b/samples/idn/idn.csproj index 984c86383..f982ff86d 100644 --- a/samples/idn/idn.csproj +++ b/samples/idn/idn.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj b/src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj index 1b2ee45bf..5fe98fc86 100644 --- a/src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj +++ b/src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj @@ -1,4 +1,4 @@ - + Discord.Net.Analyzers @@ -7,7 +7,7 @@ netstandard2.0;netstandard2.1 - + diff --git a/src/Discord.Net.Commands/Attributes/AliasAttribute.cs b/src/Discord.Net.Commands/Attributes/AliasAttribute.cs index 16eb3ba73..c4b78f534 100644 --- a/src/Discord.Net.Commands/Attributes/AliasAttribute.cs +++ b/src/Discord.Net.Commands/Attributes/AliasAttribute.cs @@ -16,7 +16,7 @@ namespace Discord.Commands /// /// [Command("stats")] /// [Alias("stat", "info")] - /// public async Task GetStatsAsync(IUser user) + /// public Task GetStatsAsync(IUser user) /// { /// // ...pull stats /// } diff --git a/src/Discord.Net.Commands/Builders/CommandBuilder.cs b/src/Discord.Net.Commands/Builders/CommandBuilder.cs index 3f1ca883a..1d946a33d 100644 --- a/src/Discord.Net.Commands/Builders/CommandBuilder.cs +++ b/src/Discord.Net.Commands/Builders/CommandBuilder.cs @@ -7,6 +7,7 @@ namespace Discord.Commands.Builders { public class CommandBuilder { + #region CommandBuilder private readonly List _preconditions; private readonly List _parameters; private readonly List _attributes; @@ -27,8 +28,9 @@ public class CommandBuilder public IReadOnlyList Parameters => _parameters; public IReadOnlyList Attributes => _attributes; public IReadOnlyList Aliases => _aliases; + #endregion - //Automatic + #region Automatic internal CommandBuilder(ModuleBuilder module) { Module = module; @@ -38,7 +40,9 @@ internal CommandBuilder(ModuleBuilder module) _attributes = new List(); _aliases = new List(); } - //User-defined + #endregion + + #region User-defined internal CommandBuilder(ModuleBuilder module, string primaryAlias, Func callback) : this(module) { @@ -132,7 +136,7 @@ internal CommandInfo Build(ModuleInfo info, CommandService service) var firstMultipleParam = _parameters.FirstOrDefault(x => x.IsMultiple); if ((firstMultipleParam != null) && (firstMultipleParam != lastParam)) throw new InvalidOperationException($"Only the last parameter in a command may have the Multiple flag. Parameter: {firstMultipleParam.Name} in {PrimaryAlias}"); - + var firstRemainderParam = _parameters.FirstOrDefault(x => x.IsRemainder); if ((firstRemainderParam != null) && (firstRemainderParam != lastParam)) throw new InvalidOperationException($"Only the last parameter in a command may have the Remainder flag. Parameter: {firstRemainderParam.Name} in {PrimaryAlias}"); @@ -140,5 +144,6 @@ internal CommandInfo Build(ModuleInfo info, CommandService service) return new CommandInfo(this, info, service); } + #endregion } } diff --git a/src/Discord.Net.Commands/Builders/ModuleBuilder.cs b/src/Discord.Net.Commands/Builders/ModuleBuilder.cs index 6dc50db31..ddb62e797 100644 --- a/src/Discord.Net.Commands/Builders/ModuleBuilder.cs +++ b/src/Discord.Net.Commands/Builders/ModuleBuilder.cs @@ -7,6 +7,7 @@ namespace Discord.Commands.Builders { public class ModuleBuilder { + #region ModuleBuilder private readonly List _commands; private readonly List _submodules; private readonly List _preconditions; @@ -27,8 +28,9 @@ public class ModuleBuilder public IReadOnlyList Aliases => _aliases; internal TypeInfo TypeInfo { get; set; } + #endregion - //Automatic + #region Automatic internal ModuleBuilder(CommandService service, ModuleBuilder parent) { Service = service; @@ -40,7 +42,9 @@ internal ModuleBuilder(CommandService service, ModuleBuilder parent) _attributes = new List(); _aliases = new List(); } - //User-defined + #endregion + + #region User-defined internal ModuleBuilder(CommandService service, ModuleBuilder parent, string primaryAlias) : this(service, parent) { @@ -132,5 +136,6 @@ private ModuleInfo BuildImpl(CommandService service, IServiceProvider services, public ModuleInfo Build(CommandService service, IServiceProvider services) => BuildImpl(service, services); internal ModuleInfo Build(CommandService service, IServiceProvider services, ModuleInfo parent) => BuildImpl(service, services, parent); + #endregion } } diff --git a/src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs b/src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs index 7a752090e..8c10ae806 100644 --- a/src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs +++ b/src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs @@ -116,7 +116,7 @@ private static void BuildModule(ModuleBuilder builder, TypeInfo typeInfo, Comman builder.AddAliases(alias.Aliases); break; case GroupAttribute group: - builder.Name = builder.Name ?? group.Prefix; + builder.Name ??= group.Prefix; builder.Group = group.Prefix; builder.AddAliases(group.Prefix); break; @@ -158,7 +158,7 @@ private static void BuildCommand(CommandBuilder builder, TypeInfo typeInfo, Meth case CommandAttribute command: builder.AddAliases(command.Text); builder.RunMode = command.RunMode; - builder.Name = builder.Name ?? command.Text; + builder.Name ??= command.Text; builder.IgnoreExtraArgs = command.IgnoreExtraArgs ?? service._ignoreExtraArgs; break; case NameAttribute name: @@ -291,7 +291,7 @@ internal static TypeReader GetTypeReader(CommandService service, Type paramType, return reader; } - //We dont have a cached type reader, create one + //We don't have a cached type reader, create one reader = ReflectionUtils.CreateObject(typeReaderType.GetTypeInfo(), service, services); service.AddTypeReader(paramType, reader, false); diff --git a/src/Discord.Net.Commands/Builders/ParameterBuilder.cs b/src/Discord.Net.Commands/Builders/ParameterBuilder.cs index 4ad5bfac0..9ee1a748c 100644 --- a/src/Discord.Net.Commands/Builders/ParameterBuilder.cs +++ b/src/Discord.Net.Commands/Builders/ParameterBuilder.cs @@ -8,6 +8,7 @@ namespace Discord.Commands.Builders { public class ParameterBuilder { + #region ParameterBuilder private readonly List _preconditions; private readonly List _attributes; @@ -24,8 +25,9 @@ public class ParameterBuilder public IReadOnlyList Preconditions => _preconditions; public IReadOnlyList Attributes => _attributes; +#endregion - //Automatic + #region Automatic internal ParameterBuilder(CommandBuilder command) { _preconditions = new List(); @@ -33,7 +35,9 @@ internal ParameterBuilder(CommandBuilder command) Command = command; } - //User-defined + #endregion + + #region User-defined internal ParameterBuilder(CommandBuilder command, string name, Type type) : this(command) { @@ -127,10 +131,11 @@ public ParameterBuilder AddPrecondition(ParameterPreconditionAttribute precondit internal ParameterInfo Build(CommandInfo info) { - if ((TypeReader ?? (TypeReader = GetReader(ParameterType))) == null) + if ((TypeReader ??= GetReader(ParameterType)) == null) throw new InvalidOperationException($"No type reader found for type {ParameterType.Name}, one must be specified"); return new ParameterInfo(this, info, Command.Module.Service); } + #endregion } } diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index 8659b0130..db08d0d79 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -29,6 +29,7 @@ namespace Discord.Commands /// public class CommandService : IDisposable { + #region CommandService ///

/// Occurs when a command-related information is received. /// @@ -131,8 +132,9 @@ public CommandService(CommandServiceConfig config) entityTypeReaders.Add((typeof(IUser), typeof(UserTypeReader<>))); _entityTypeReaders = entityTypeReaders.ToImmutable(); } + #endregion - //Modules + #region Modules public async Task CreateModuleAsync(string primaryAlias, Action buildFunc) { await _moduleLock.WaitAsync().ConfigureAwait(false); @@ -187,7 +189,7 @@ public async Task CreateModuleAsync(string primaryAlias, Action public async Task AddModuleAsync(Type type, IServiceProvider services) { - services = services ?? EmptyServiceProvider.Instance; + services ??= EmptyServiceProvider.Instance; await _moduleLock.WaitAsync().ConfigureAwait(false); try @@ -222,7 +224,7 @@ public async Task AddModuleAsync(Type type, IServiceProvider service /// public async Task> AddModulesAsync(Assembly assembly, IServiceProvider services) { - services = services ?? EmptyServiceProvider.Instance; + services ??= EmptyServiceProvider.Instance; await _moduleLock.WaitAsync().ConfigureAwait(false); try @@ -322,8 +324,9 @@ private bool RemoveModuleInternal(ModuleInfo module) return true; } + #endregion - //Type Readers + #region Type Readers /// /// Adds a custom to this for the supplied object /// type. @@ -448,8 +451,9 @@ internal TypeReader GetDefaultTypeReader(Type type) } return null; } + #endregion - //Execution + #region Execution /// /// Searches for the command. /// @@ -503,7 +507,7 @@ public Task ExecuteAsync(ICommandContext context, int argPos, IServiceP /// public async Task ExecuteAsync(ICommandContext context, string input, IServiceProvider services, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception) { - services = services ?? EmptyServiceProvider.Instance; + services ??= EmptyServiceProvider.Instance; var searchResult = Search(input); if (!searchResult.IsSuccess) @@ -598,11 +602,13 @@ float CalculateScore(CommandMatch match, ParseResult parseResult) //If we get this far, at least one parse was successful. Execute the most likely overload. var chosenOverload = successfulParses[0]; var result = await chosenOverload.Key.ExecuteAsync(context, chosenOverload.Value, services).ConfigureAwait(false); - if (!result.IsSuccess && !(result is RuntimeResult || result is ExecuteResult)) // succesful results raise the event in CommandInfo#ExecuteInternalAsync (have to raise it there b/c deffered execution) + if (!result.IsSuccess && !(result is RuntimeResult || result is ExecuteResult)) // successful results raise the event in CommandInfo#ExecuteInternalAsync (have to raise it there b/c deferred execution) await _commandExecutedEvent.InvokeAsync(chosenOverload.Key.Command, context, result); return result; } + #endregion + #region Dispose protected virtual void Dispose(bool disposing) { if (!_isDisposed) @@ -620,5 +626,6 @@ void IDisposable.Dispose() { Dispose(true); } + #endregion } } diff --git a/src/Discord.Net.Commands/Discord.Net.Commands.csproj b/src/Discord.Net.Commands/Discord.Net.Commands.csproj index 21869d91c..ec2795de2 100644 --- a/src/Discord.Net.Commands/Discord.Net.Commands.csproj +++ b/src/Discord.Net.Commands/Discord.Net.Commands.csproj @@ -12,4 +12,4 @@ - + \ No newline at end of file diff --git a/src/Discord.Net.Commands/Extensions/MessageExtensions.cs b/src/Discord.Net.Commands/Extensions/MessageExtensions.cs index f880e1d98..9aa83d418 100644 --- a/src/Discord.Net.Commands/Extensions/MessageExtensions.cs +++ b/src/Discord.Net.Commands/Extensions/MessageExtensions.cs @@ -51,8 +51,7 @@ public static bool HasMentionPrefix(this IUserMessage msg, IUser user, ref int a if (endPos == -1) return false; if (text.Length < endPos + 2 || text[endPos + 1] != ' ') return false; //Must end in "> " - ulong userId; - if (!MentionUtils.TryParseUser(text.Substring(0, endPos + 1), out userId)) return false; + if (!MentionUtils.TryParseUser(text.Substring(0, endPos + 1), out ulong userId)) return false; if (userId == user.Id) { argPos = endPos + 2; diff --git a/src/Discord.Net.Commands/Info/CommandInfo.cs b/src/Discord.Net.Commands/Info/CommandInfo.cs index 3bcef9831..773c7c773 100644 --- a/src/Discord.Net.Commands/Info/CommandInfo.cs +++ b/src/Discord.Net.Commands/Info/CommandInfo.cs @@ -123,7 +123,7 @@ internal CommandInfo(CommandBuilder builder, ModuleInfo module, CommandService s public async Task CheckPreconditionsAsync(ICommandContext context, IServiceProvider services = null) { - services = services ?? EmptyServiceProvider.Instance; + services ??= EmptyServiceProvider.Instance; async Task CheckGroups(IEnumerable preconditions, string type) { @@ -164,7 +164,7 @@ async Task CheckGroups(IEnumerable pr public async Task ParseAsync(ICommandContext context, int startIndex, SearchResult searchResult, PreconditionResult preconditionResult = null, IServiceProvider services = null) { - services = services ?? EmptyServiceProvider.Instance; + services ??= EmptyServiceProvider.Instance; if (!searchResult.IsSuccess) return ParseResult.FromError(searchResult); @@ -201,7 +201,7 @@ public Task ExecuteAsync(ICommandContext context, ParseResult parseResu } public async Task ExecuteAsync(ICommandContext context, IEnumerable argList, IEnumerable paramList, IServiceProvider services) { - services = services ?? EmptyServiceProvider.Instance; + services ??= EmptyServiceProvider.Instance; try { diff --git a/src/Discord.Net.Commands/Info/ParameterInfo.cs b/src/Discord.Net.Commands/Info/ParameterInfo.cs index b435b301a..a6ba9dfde 100644 --- a/src/Discord.Net.Commands/Info/ParameterInfo.cs +++ b/src/Discord.Net.Commands/Info/ParameterInfo.cs @@ -75,7 +75,7 @@ internal ParameterInfo(ParameterBuilder builder, CommandInfo command, CommandSer public async Task CheckPreconditionsAsync(ICommandContext context, object arg, IServiceProvider services = null) { - services = services ?? EmptyServiceProvider.Instance; + services ??= EmptyServiceProvider.Instance; foreach (var precondition in Preconditions) { @@ -89,7 +89,7 @@ public async Task CheckPreconditionsAsync(ICommandContext co public async Task ParseAsync(ICommandContext context, string input, IServiceProvider services = null) { - services = services ?? EmptyServiceProvider.Instance; + services ??= EmptyServiceProvider.Instance; return await _reader.ReadAsync(context, input, services).ConfigureAwait(false); } diff --git a/src/Discord.Net.Commands/ModuleBase.cs b/src/Discord.Net.Commands/ModuleBase.cs index 6ec2db54d..3eddc11d2 100644 --- a/src/Discord.Net.Commands/ModuleBase.cs +++ b/src/Discord.Net.Commands/ModuleBase.cs @@ -16,6 +16,7 @@ public abstract class ModuleBase : ModuleBase { } public abstract class ModuleBase : IModuleBase where T : class, ICommandContext { + #region ModuleBase /// /// The underlying context of the command. /// @@ -35,10 +36,14 @@ public abstract class ModuleBase : IModuleBase /// Specifies if notifications are sent for mentioned users and roles in the . /// If null, all mentioned roles and users will be notified. /// + /// The request options for this request. /// The message references to be included. Used to reply to specific messages. - protected virtual async Task ReplyAsync(string message = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null) + /// The message components to be included with this message. Used for interactions. + /// A collection of stickers to send with the file. + /// A array of s to send with this response. Max 10. + protected virtual async Task ReplyAsync(string message = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) { - return await Context.Channel.SendMessageAsync(message, isTTS, embed, options, allowedMentions, messageReference).ConfigureAwait(false); + return await Context.Channel.SendMessageAsync(message, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); } /// /// The method to execute before executing the command. @@ -63,8 +68,9 @@ protected virtual void AfterExecute(CommandInfo command) protected virtual void OnModuleBuilding(CommandService commandService, ModuleBuilder builder) { } + #endregion - //IModuleBase + #region IModuleBase void IModuleBase.SetContext(ICommandContext context) { var newValue = context as T; @@ -73,5 +79,6 @@ void IModuleBase.SetContext(ICommandContext context) void IModuleBase.BeforeExecute(CommandInfo command) => BeforeExecute(command); void IModuleBase.AfterExecute(CommandInfo command) => AfterExecute(command); void IModuleBase.OnModuleBuilding(CommandService commandService, ModuleBuilder builder) => OnModuleBuilding(commandService, builder); + #endregion } } diff --git a/src/Discord.Net.Commands/RunMode.cs b/src/Discord.Net.Commands/RunMode.cs index 8e230b500..d6b49065b 100644 --- a/src/Discord.Net.Commands/RunMode.cs +++ b/src/Discord.Net.Commands/RunMode.cs @@ -8,7 +8,7 @@ namespace Discord.Commands public enum RunMode { /// - /// The default behaviour set in . + /// The default behavior set in . /// Default, /// diff --git a/src/Discord.Net.Core/CDN.cs b/src/Discord.Net.Core/CDN.cs index e1e8e5e1a..d6535a4f1 100644 --- a/src/Discord.Net.Core/CDN.cs +++ b/src/Discord.Net.Core/CDN.cs @@ -46,6 +46,32 @@ public static string GetUserAvatarUrl(ulong userId, string avatarId, ushort size string extension = FormatToExtension(format, avatarId); return $"{DiscordConfig.CDNUrl}avatars/{userId}/{avatarId}.{extension}?size={size}"; } + + public static string GetGuildUserAvatarUrl(ulong userId, ulong guildId, string avatarId, ushort size, ImageFormat format) + { + if (avatarId == null) + return null; + string extension = FormatToExtension(format, avatarId); + return $"{DiscordConfig.CDNUrl}guilds/{guildId}/users/{userId}/avatars/{avatarId}.{extension}?size={size}"; + } + + /// + /// Returns a user banner URL. + /// + /// The user snowflake identifier. + /// The banner identifier. + /// The size of the image to return in horizontal pixels. This can be any power of two between 16 and 2048. + /// The format to return. + /// + /// A URL pointing to the user's banner in the specified size. + /// + public static string GetUserBannerUrl(ulong userId, string bannerId, ushort size, ImageFormat format) + { + if (bannerId == null) + return null; + string extension = FormatToExtension(format, bannerId); + return $"{DiscordConfig.CDNUrl}banners/{userId}/{bannerId}.{extension}?size={size}"; + } /// /// Returns the default user avatar URL. /// @@ -68,6 +94,16 @@ public static string GetDefaultUserAvatarUrl(ushort discriminator) public static string GetGuildIconUrl(ulong guildId, string iconId) => iconId != null ? $"{DiscordConfig.CDNUrl}icons/{guildId}/{iconId}.jpg" : null; /// + /// Returns a guild role's icon URL. + /// + /// The role identifier. + /// The icon hash. + /// + /// A URL pointing to the guild role's icon. + /// + public static string GetGuildRoleIconUrl(ulong roleId, string roleHash) + => roleHash != null ? $"{DiscordConfig.CDNUrl}role-icons/{roleId}/{roleHash}.png" : null; + /// /// Returns a guild splash URL. /// /// The guild snowflake identifier. @@ -103,15 +139,17 @@ public static string GetChannelIconUrl(ulong channelId, string iconId) /// /// The guild snowflake identifier. /// The banner image identifier. + /// The format to return. /// The size of the image to return in horizontal pixels. This can be any power of two between 16 and 2048 inclusive. /// /// A URL pointing to the guild's banner image. /// - public static string GetGuildBannerUrl(ulong guildId, string bannerId, ushort? size = null) + public static string GetGuildBannerUrl(ulong guildId, string bannerId, ImageFormat format, ushort? size = null) { - if (!string.IsNullOrEmpty(bannerId)) - return $"{DiscordConfig.CDNUrl}banners/{guildId}/{bannerId}.jpg" + (size.HasValue ? $"?size={size}" : string.Empty); - return null; + if (string.IsNullOrEmpty(bannerId)) + return null; + string extension = FormatToExtension(format, bannerId); + return $"{DiscordConfig.CDNUrl}banners/{guildId}/{bannerId}.{extension}" + (size.HasValue ? $"?size={size}" : string.Empty); } /// /// Returns an emoji URL. @@ -159,23 +197,39 @@ public static string GetSpotifyAlbumArtUrl(string albumArtId) public static string GetSpotifyDirectUrl(string trackId) => $"https://open.spotify.com/track/{trackId}"; + /// + /// Gets a stickers url based off the id and format. + /// + /// The id of the sticker. + /// The format of the sticker. + /// + /// A URL to the sticker. + /// + public static string GetStickerUrl(ulong stickerId, StickerFormatType format = StickerFormatType.Png) + => $"{DiscordConfig.CDNUrl}stickers/{stickerId}.{FormatToExtension(format)}"; + + private static string FormatToExtension(StickerFormatType format) + { + return format switch + { + StickerFormatType.None or StickerFormatType.Png or StickerFormatType.Apng => "png", // In the case of the Sticker endpoint, the sticker will be available as PNG if its format_type is PNG or APNG, and as Lottie if its format_type is LOTTIE. + StickerFormatType.Lottie => "lottie", + _ => throw new ArgumentException(nameof(format)), + }; + } + private static string FormatToExtension(ImageFormat format, string imageId) { if (format == ImageFormat.Auto) format = imageId.StartsWith("a_") ? ImageFormat.Gif : ImageFormat.Png; - switch (format) + return format switch { - case ImageFormat.Gif: - return "gif"; - case ImageFormat.Jpeg: - return "jpeg"; - case ImageFormat.Png: - return "png"; - case ImageFormat.WebP: - return "webp"; - default: - throw new ArgumentException(nameof(format)); - } + ImageFormat.Gif => "gif", + ImageFormat.Jpeg => "jpeg", + ImageFormat.Png => "png", + ImageFormat.WebP => "webp", + _ => throw new ArgumentException(nameof(format)), + }; } } } diff --git a/src/Discord.Net.Core/Discord.Net.Core.csproj b/src/Discord.Net.Core/Discord.Net.Core.csproj index bc513390c..29868e1c7 100644 --- a/src/Discord.Net.Core/Discord.Net.Core.csproj +++ b/src/Discord.Net.Core/Discord.Net.Core.csproj @@ -1,4 +1,4 @@ - + @@ -16,4 +16,4 @@ all - + \ No newline at end of file diff --git a/src/Discord.Net.Core/DiscordConfig.cs b/src/Discord.Net.Core/DiscordConfig.cs index da8525644..d5951bd07 100644 --- a/src/Discord.Net.Core/DiscordConfig.cs +++ b/src/Discord.Net.Core/DiscordConfig.cs @@ -94,6 +94,13 @@ public class DiscordConfig /// The maximum number of users that can be gotten per-batch. /// public const int MaxUsersPerBatch = 1000; + /// + /// Returns the max users allowed to be in a request for guild event users. + /// + /// + /// The maximum number of users that can be gotten per-batch. + /// + public const int MaxGuildEventUsersPerBatch = 100; /// /// Returns the max guilds allowed to be in a request. /// @@ -158,5 +165,17 @@ public class DiscordConfig /// clock. Your system will still need a stable clock. /// public bool UseSystemClock { get; set; } = true; + + /// + /// Gets or sets whether or not the internal experation check uses the system date + /// + snowflake date to check if an interaction can be responded to. + /// + /// + /// If set to then the CreatedAt property in an interaction + /// will be set to when it was received instead of the snowflakes date. + ///
+ /// This will still require a stable clock on your system. + ///
+ public bool UseInteractionSnowflakeDate { get; set; } = true; } } diff --git a/src/Discord.Net.Core/DiscordErrorCode.cs b/src/Discord.Net.Core/DiscordErrorCode.cs new file mode 100644 index 000000000..5a5223b93 --- /dev/null +++ b/src/Discord.Net.Core/DiscordErrorCode.cs @@ -0,0 +1,197 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents a set of json error codes received by discord. + /// + public enum DiscordErrorCode + { + GeneralError = 0, + + #region UnknownXYZ (10XXX) + UnknownAccount = 10001, + UnknownApplication = 10002, + UnknownChannel = 10003, + UnknownGuild = 10004, + UnknownIntegration = 10005, + UnknownInvite = 10006, + UnknownMember = 10007, + UnknownMessage = 10008, + UnknownPermissionOverwrite = 10009, + UnknownProvider = 10010, + UnknownRole = 10011, + UnknownToken = 10012, + UnknownUser = 10013, + UnknownEmoji = 10014, + UnknownWebhook = 10015, + UnknownWebhookService = 10016, + UnknownSession = 10020, + UnknownBan = 10026, + UnknownSKU = 10027, + UnknownStoreListing = 10028, + UnknownEntitlement = 10029, + UnknownBuild = 10030, + UnknownLobby = 10031, + UnknownBranch = 10032, + UnknownStoreDirectoryLayout = 10033, + UnknownRedistributable = 10036, + UnknownGiftCode = 10038, + UnknownStream = 10049, + UnknownPremiumServerSubscribeCooldown = 10050, + UnknownGuildTemplate = 10057, + UnknownDiscoverableServerCategory = 10059, + UnknownSticker = 10060, + UnknownInteraction = 10062, + UnknownApplicationCommand = 10063, + UnknownApplicationCommandPermissions = 10066, + UnknownStageInstance = 10067, + UnknownGuildMemberVerificationForm = 10068, + UnknownGuildWelcomeScreen = 10069, + UnknownGuildScheduledEvent = 10070, + UnknownGuildScheduledEventUser = 10071, + #endregion + + #region General Actions (20XXX) + BotsCannotUse = 20001, + OnlyBotsCanUse = 20002, + CannotSendExplicitContent = 20009, + ApplicationActionUnauthorized = 20012, + ActionSlowmode = 20016, + OnlyOwnerAction = 20018, + AnnouncementEditRatelimit = 20022, + ChannelWriteRatelimit = 20028, + WordsNotAllowed = 20031, + GuildPremiumTooLow = 20035, + #endregion + + #region Numeric Limits Reached (30XXX) + MaximumGuildsReached = 30001, + MaximumFriendsReached = 30002, + MaximumPinsReached = 30003, + MaximumRecipientsReached = 30004, + MaximumGuildRolesReached = 30005, + MaximumWebhooksReached = 30007, + MaximumEmojisReached = 30008, + MaximumReactionsReached = 30010, + MaximumGuildChannelsReached = 30013, + MaximumAttachmentsReached = 30015, + MaximumInvitesReached = 30016, + MaximumAnimatedEmojisReached = 30018, + MaximumServerMembersReached = 30019, + MaximumServerCategoriesReached = 30030, + GuildTemplateAlreadyExists = 30031, + MaximumThreadMembersReached = 30033, + MaximumBansForNonGuildMembersReached = 30035, + MaximumBanFetchesReached = 30037, + MaximumUncompleteGuildScheduledEvents = 30038, + MaximumStickersReached = 30039, + MaximumPruneRequestReached = 30040, + MaximumGuildWigitsReached = 30042, + #endregion + + #region General Request Errors (40XXX) + TokenUnauthorized = 40001, + InvalidVerification = 40002, + OpeningDMTooFast = 40003, + RequestEntityTooLarge = 40005, + FeatureDisabled = 40006, + UserBanned = 40007, + TargetUserNotInVoice = 40032, + MessageAlreadyCrossposted = 40033, + ApplicationNameAlreadyExists = 40041, + #endregion + + #region Action Preconditions/Checks (50XXX) + MissingPermissions = 50001, + InvalidAccountType = 50002, + CannotExecuteForDM = 50003, + GuildWigitDisabled = 50004, + CannotEditOtherUsersMessage = 50005, + CannotSendEmptyMessage = 50006, + CannotSendMessageToUser = 50007, + CannotSendMessageToVoiceChannel = 50008, + ChannelVerificationTooHight = 50009, + OAuth2ApplicationDoesntHaveBot = 50010, + OAuth2ApplicationLimitReached = 50011, + InvalidOAuth2State = 50012, + InsufficientPermissions = 50013, + InvalidAuthenticationToken = 50014, + NoteTooLong = 50015, + ProvidedMessageDeleteCountOutOfBounds = 50016, + InvalidPinChannel = 50019, + InvalidInvite = 50020, + CannotExecuteOnSystemMessage = 50021, + CannotExecuteOnChannelType = 50024, + InvalidOAuth2Token = 50025, + MissingOAuth2Scope = 50026, + InvalidWebhookToken = 50027, + InvalidRole = 50028, + InvalidRecipients = 50033, + BulkDeleteMessageTooOld = 50034, + InvalidFormBody = 50035, + InviteAcceptedForGuildThatBotIsntIn = 50036, + InvalidAPIVersion = 50041, + FileUploadTooBig = 50045, + InvalidFileUpload = 50046, + CannotSelfRedeemGift = 50054, + PaymentSourceRequiredForGift = 50070, + CannotDeleteRequiredCommunityChannel = 50074, + InvalidSticker = 50081, + CannotExecuteOnArchivedThread = 50083, + InvalidThreadNotificationSettings = 50084, + BeforeValueEarlierThanThreadCreation = 50085, + ServerLocaleUnavailable = 50095, + ServerRequiresMonetization = 50097, + ServerRequiresBoosts = 50101, + + #endregion + + #region 2FA (60XXX) + Requires2FA = 60003, + #endregion + + #region User Searches (80XXX) + NoUsersWithTag = 80004, + #endregion + + #region Reactions (90XXX) + ReactionBlocked = 90001, + #endregion + + #region API Status (130XXX) + APIOverloaded = 130000, + #endregion + + #region Stage Errors (150XXX) + StageAlreadyOpened = 150006, + #endregion + + #region Reply and Thread Errors (160XXX) + CannotReplyWithoutReadMessageHistory = 160002, + MessageAlreadyContainsThread = 160004, + ThreadIsLocked = 160005, + MaximumActiveThreadsReached = 160006, + MaximumAnnouncementThreadsReached = 160007, + #endregion + + #region Sticker Uploads (170XXX) + InvalidJSONLottie = 170001, + LottieCantContainRasters = 170002, + StickerMaximumFramerateExceeded = 170003, + StickerMaximumFrameCountExceeded = 170004, + LottieMaximumDimentionsExceeded = 170005, + StickerFramerateBoundsExceeed = 170006, + StickerAnimationDurationTooLong = 170007, + #endregion + + #region Guild Scheduled Events + CannotUpdateFinishedEvent = 180000, + FailedStageCreation = 180002, + #endregion + } +} diff --git a/src/Discord.Net.Core/DiscordJsonError.cs b/src/Discord.Net.Core/DiscordJsonError.cs new file mode 100644 index 000000000..fdf82ea0c --- /dev/null +++ b/src/Discord.Net.Core/DiscordJsonError.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents a generic parsed json error received from discord after performing a rest request. + /// + public struct DiscordJsonError + { + /// + /// Gets the json path of the error. + /// + public string Path { get; } + + /// + /// Gets a collection of errors associated with the specific property at the path. + /// + public IReadOnlyCollection Errors { get; } + + internal DiscordJsonError(string path, DiscordError[] errors) + { + Path = path; + Errors = errors.ToImmutableArray(); + } + } + + /// + /// Represents an error with a property. + /// + public struct DiscordError + { + /// + /// Gets the code of the error. + /// + public string Code { get; } + + /// + /// Gets the message describing what went wrong. + /// + public string Message { get; } + + internal DiscordError(string code, string message) + { + Code = code; + Message = message; + } + } +} diff --git a/src/Discord.Net.Core/Entities/Activities/ActivityProperties.cs b/src/Discord.Net.Core/Entities/Activities/ActivityProperties.cs index a7d13235f..15a79dff6 100644 --- a/src/Discord.Net.Core/Entities/Activities/ActivityProperties.cs +++ b/src/Discord.Net.Core/Entities/Activities/ActivityProperties.cs @@ -33,6 +33,18 @@ public enum ActivityProperties /// /// Indicates that a user can play this song. /// - Play = 0b100000 + Play = 0b100000, + /// + /// Indicates that a user is playing an activity in a voice channel with friends. + /// + PartyPrivacyFriends = 0b1000000, + /// + /// Indicates that a user is playing an activity in a voice channel. + /// + PartyPrivacyVoiceChannel = 0b10000000, + /// + /// Indicates that a user is playing an activity in a voice channel. + /// + Embedded = 0b10000000 } } diff --git a/src/Discord.Net.Core/Entities/Activities/ActivityType.cs b/src/Discord.Net.Core/Entities/Activities/ActivityType.cs index 8c44f49e3..1f67886eb 100644 --- a/src/Discord.Net.Core/Entities/Activities/ActivityType.cs +++ b/src/Discord.Net.Core/Entities/Activities/ActivityType.cs @@ -25,5 +25,9 @@ public enum ActivityType /// The user has set a custom status. ///
CustomStatus = 4, + /// + /// The user is competing in a game. + /// + Competing = 5, } } diff --git a/src/Discord.Net.Core/Entities/ApplicationFlags.cs b/src/Discord.Net.Core/Entities/ApplicationFlags.cs new file mode 100644 index 000000000..1ede4257d --- /dev/null +++ b/src/Discord.Net.Core/Entities/ApplicationFlags.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents public flags for an application. + /// + public enum ApplicationFlags + { + GatewayPresence = 1 << 12, + GatewayPresenceLimited = 1 << 13, + GatewayGuildMembers = 1 << 14, + GatewayGuildMembersLimited = 1 << 15, + VerificationPendingGuildLimit = 1 << 16, + Embedded = 1 << 17, + GatewayMessageContent = 1 << 18, + GatewayMessageContentLimited = 1 << 19 + } +} diff --git a/src/Discord.Net.Core/Entities/ApplicationInstallParams.cs b/src/Discord.Net.Core/Entities/ApplicationInstallParams.cs new file mode 100644 index 000000000..180592f1e --- /dev/null +++ b/src/Discord.Net.Core/Entities/ApplicationInstallParams.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents install parameters for an application. + /// + public class ApplicationInstallParams + { + /// + /// Gets the scopes to install this application. + /// + public IReadOnlyCollection Scopes { get; } + + /// + /// Gets the default permissions to install this application + /// + public GuildPermission? Permission { get; } + + internal ApplicationInstallParams(string[] scopes, GuildPermission? permission) + { + Scopes = scopes.ToImmutableArray(); + Permission = permission; + } + } +} diff --git a/src/Discord.Net.Core/Entities/AuditLogs/ActionType.cs b/src/Discord.Net.Core/Entities/AuditLogs/ActionType.cs index 1728b2021..5092b4e7f 100644 --- a/src/Discord.Net.Core/Entities/AuditLogs/ActionType.cs +++ b/src/Discord.Net.Core/Entities/AuditLogs/ActionType.cs @@ -142,5 +142,55 @@ public enum ActionType /// A message was unpinned from this guild. ///
MessageUnpinned = 75, + + /// + /// A integration was created + /// + IntegrationCreated = 80, + /// + /// A integration was updated + /// + IntegrationUpdated = 81, + /// + /// An integration was deleted + /// + IntegrationDeleted = 82, + /// + /// A stage instance was created. + /// + StageInstanceCreated = 83, + /// + /// A stage instance was updated. + /// + StageInstanceUpdated = 84, + /// + /// A stage instance was deleted. + /// + StageInstanceDeleted = 85, + + /// + /// A sticker was created. + /// + StickerCreated = 90, + /// + /// A sticker was updated. + /// + StickerUpdated = 91, + /// + /// A sticker was deleted. + /// + StickerDeleted = 92, + /// + /// A thread was created. + /// + ThreadCreate = 110, + /// + /// A thread was updated. + /// + ThreadUpdate = 111, + /// + /// A thread was deleted. + /// + ThreadDelete = 112 } } diff --git a/src/Discord.Net.Core/Entities/Channels/ChannelType.cs b/src/Discord.Net.Core/Entities/Channels/ChannelType.cs index 6dd910ba6..e60bd5031 100644 --- a/src/Discord.Net.Core/Entities/Channels/ChannelType.cs +++ b/src/Discord.Net.Core/Entities/Channels/ChannelType.cs @@ -14,6 +14,18 @@ public enum ChannelType /// The channel is a category channel. Category = 4, /// The channel is a news channel. - News = 5 + News = 5, + /// The channel is a store channel. + Store = 6, + /// The channel is a temporary thread channel under a news channel. + NewsThread = 10, + /// The channel is a temporary thread channel under a text channel. + PublicThread = 11, + /// The channel is a private temporary thread channel under a text channel. + PrivateThread = 12, + /// The channel is a stage voice channel. + Stage = 13, + /// The channel is a guild directory used in hub servers. (Unreleased) + GuildDirectory = 14 } } diff --git a/src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs b/src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs index e60eb9c13..87dfb3460 100644 --- a/src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs @@ -28,11 +28,14 @@ public interface IMessageChannel : IChannel /// If null, all mentioned roles and users will be notified. /// /// The message references to be included. Used to reply to specific messages. + /// The message components to be included with this message. Used for interactions. + /// A collection of stickers to send with the message. + /// A array of s to send with this response. Max 10. /// /// A task that represents an asynchronous send operation for delivering the message. The task result /// contains the sent message. /// - Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null); + Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null); /// /// Sends a file to this message channel with an optional caption. /// @@ -65,11 +68,14 @@ public interface IMessageChannel : IChannel /// If null, all mentioned roles and users will be notified. /// /// The message references to be included. Used to reply to specific messages. + /// The message components to be included with this message. Used for interactions. + /// A collection of stickers to send with the file. + /// A array of s to send with this response. Max 10. /// /// A task that represents an asynchronous send operation for delivering the message. The task result /// contains the sent message. /// - Task SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null); + Task SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null); /// /// Sends a file to this message channel with an optional caption. /// @@ -99,11 +105,72 @@ public interface IMessageChannel : IChannel /// If null, all mentioned roles and users will be notified. /// /// The message references to be included. Used to reply to specific messages. + /// The message components to be included with this message. Used for interactions. + /// A collection of stickers to send with the file. + /// A array of s to send with this response. Max 10. /// /// A task that represents an asynchronous send operation for delivering the message. The task result /// contains the sent message. /// - Task SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null); + Task SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null); + /// + /// Sends a file to this message channel with an optional caption. + /// + /// + /// This method sends a file as if you are uploading an attachment directly from your Discord client. + /// + /// If you wish to upload an image and have it embedded in a embed, + /// you may upload the file and refer to the file with "attachment://filename.ext" in the + /// . See the example section for its usage. + /// + /// + /// The attachment containing the file and description. + /// The message to be sent. + /// Whether the message should be read aloud by Discord or not. + /// The to be sent. + /// The options to be used when sending the request. + /// + /// Specifies if notifications are sent for mentioned users and roles in the message . + /// If null, all mentioned roles and users will be notified. + /// + /// The message references to be included. Used to reply to specific messages. + /// The message components to be included with this message. Used for interactions. + /// A collection of stickers to send with the file. + /// A array of s to send with this response. Max 10. + /// + /// A task that represents an asynchronous send operation for delivering the message. The task result + /// contains the sent message. + /// + Task SendFileAsync(FileAttachment attachment, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null); + /// + /// Sends a collection of files to this message channel. + /// + /// + /// This method sends files as if you are uploading attachments directly from your Discord client. + /// + /// If you wish to upload an image and have it embedded in a embed, + /// you may upload the file and refer to the file with "attachment://filename.ext" in the + /// . See the example section for its usage. + /// + /// + /// A collection of attachments to upload. + /// The message to be sent. + /// Whether the message should be read aloud by Discord or not. + /// The to be sent. + /// The options to be used when sending the request. + /// + /// Specifies if notifications are sent for mentioned users and roles in the message . + /// If null, all mentioned roles and users will be notified. + /// + /// The message references to be included. Used to reply to specific messages. + /// The message components to be included with this message. Used for interactions. + /// A collection of stickers to send with the file. + /// A array of s to send with this response. Max 10. + /// + /// A task that represents an asynchronous send operation for delivering the message. The task result + /// contains the sent message. + /// + Task SendFilesAsync(IEnumerable attachments, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null); /// /// Gets a message from this message channel. diff --git a/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs b/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs index 2c9503db1..563acd4f8 100644 --- a/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs @@ -12,7 +12,7 @@ public interface INestedChannel : IGuildChannel /// Gets the parent (category) ID of this channel in the guild's channel list. /// /// - /// A representing the snowflake identifier of the parent of this channel; + /// A representing the snowflake identifier of the parent of this channel; /// null if none is set. /// ulong? CategoryId { get; } @@ -56,6 +56,50 @@ public interface INestedChannel : IGuildChannel /// metadata object containing information for the created invite. /// Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null); + + /// + /// Creates a new invite to this channel. + /// + /// + /// The following example creates a new invite to this channel; the invite lasts for 12 hours and can only + /// be used 3 times throughout its lifespan. + /// + /// await guildChannel.CreateInviteAsync(maxAge: 43200, maxUses: 3); + /// + /// + /// The id of the embedded application to open for this invite. + /// The time (in seconds) until the invite expires. Set to null to never expire. + /// The max amount of times this invite may be used. Set to null to have unlimited uses. + /// If true, the user accepting this invite will be kicked from the guild after closing their client. + /// If true, don't try to reuse a similar invite (useful for creating many unique one time use invites). + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous invite creation operation. The task result contains an invite + /// metadata object containing information for the created invite. + /// + Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null); + + /// + /// Creates a new invite to this channel. + /// + /// + /// The following example creates a new invite to this channel; the invite lasts for 12 hours and can only + /// be used 3 times throughout its lifespan. + /// + /// await guildChannel.CreateInviteAsync(maxAge: 43200, maxUses: 3); + /// + /// + /// The id of the user whose stream to display for this invite. + /// The time (in seconds) until the invite expires. Set to null to never expire. + /// The max amount of times this invite may be used. Set to null to have unlimited uses. + /// If true, the user accepting this invite will be kicked from the guild after closing their client. + /// If true, don't try to reuse a similar invite (useful for creating many unique one time use invites). + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous invite creation operation. The task result contains an invite + /// metadata object containing information for the created invite. + /// + Task CreateInviteToStreamAsync(IUser user, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null); /// /// Gets a collection of all invites to this channel. /// B diff --git a/src/Discord.Net.Core/Entities/Channels/IStageChannel.cs b/src/Discord.Net.Core/Entities/Channels/IStageChannel.cs new file mode 100644 index 000000000..5e0be5b7e --- /dev/null +++ b/src/Discord.Net.Core/Entities/Channels/IStageChannel.cs @@ -0,0 +1,114 @@ +using System; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents a generic Stage Channel. + /// + public interface IStageChannel : IVoiceChannel + { + /// + /// Gets the topic of the Stage instance. + /// + /// + /// If the stage isn't live then this property will be set to . + /// + string Topic { get; } + + /// + /// Gets the of the current stage. + /// + /// + /// If the stage isn't live then this property will be set to . + /// + StagePrivacyLevel? PrivacyLevel { get; } + + /// + /// Gets whether or not stage discovery is disabled. + /// + bool? IsDiscoverableDisabled { get; } + + /// + /// Gets whether or not the stage is live. + /// + bool IsLive { get; } + + /// + /// Starts the stage, creating a stage instance. + /// + /// The topic for the stage/ + /// The privacy level of the stage. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous start operation. + /// + Task StartStageAsync(string topic, StagePrivacyLevel privacyLevel = StagePrivacyLevel.GuildOnly, RequestOptions options = null); + + /// + /// Modifies the current stage instance. + /// + /// The properties to modify the stage instance with. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous modify operation. + /// + Task ModifyInstanceAsync(Action func, RequestOptions options = null); + + /// + /// Stops the stage, deleting the stage instance. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous stop operation. + /// + Task StopStageAsync(RequestOptions options = null); + + /// + /// Indicates that the bot would like to speak within a stage channel. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous request to speak operation. + /// + Task RequestToSpeakAsync(RequestOptions options = null); + + /// + /// Makes the current user become a speaker within a stage. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous speaker modify operation. + /// + Task BecomeSpeakerAsync(RequestOptions options = null); + + /// + /// Makes the current user a listener. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous stop operation. + /// + Task StopSpeakingAsync(RequestOptions options = null); + + /// + /// Makes a user a speaker within a stage. + /// + /// The user to make the speaker. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous move operation. + /// + Task MoveToSpeakerAsync(IGuildUser user, RequestOptions options = null); + + /// + /// Removes a user from speaking. + /// + /// The user to remove from speaking. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous remove operation. + /// + Task RemoveFromSpeakerAsync(IGuildUser user, RequestOptions options = null); + } +} diff --git a/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs b/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs index a2baf6990..ae0fe674b 100644 --- a/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs @@ -114,5 +114,40 @@ public interface ITextChannel : IMessageChannel, IMentionable, INestedChannel /// of webhooks that is available in this channel. /// Task> GetWebhooksAsync(RequestOptions options = null); + + /// + /// Creates a thread within this . + /// + /// + /// When is the thread type will be based off of the + /// channel its created in. When called on a , it creates a . + /// When called on a , it creates a . The id of the created + /// thread will be the same as the id of the message, and as such a message can only have a + /// single thread created from it. + /// + /// The name of the thread. + /// + /// The type of the thread. + /// + /// Note: This parameter is not used if the parameter is not specified. + /// + /// + /// + /// The duration on which this thread archives after. + /// + /// Note: Options and + /// are only available for guilds that are boosted. You can check in the to see if the + /// guild has the THREE_DAY_THREAD_ARCHIVE and SEVEN_DAY_THREAD_ARCHIVE. + /// + /// + /// The message which to start the thread from. + /// Whether non-moderators can add other non-moderators to a thread; only available when creating a private thread + /// The amount of seconds a user has to wait before sending another message (0-21600) + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous create operation. The task result contains a + /// + Task CreateThreadAsync(string name, ThreadType type = ThreadType.PublicThread, ThreadArchiveDuration autoArchiveDuration = ThreadArchiveDuration.OneDay, + IMessage message = null, bool? invitable = null, int? slowmode = null, RequestOptions options = null); } } diff --git a/src/Discord.Net.Core/Entities/Channels/IThreadChannel.cs b/src/Discord.Net.Core/Entities/Channels/IThreadChannel.cs new file mode 100644 index 000000000..50e46efa6 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Channels/IThreadChannel.cs @@ -0,0 +1,89 @@ +using System; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents a thread channel inside of a guild. + /// + public interface IThreadChannel : ITextChannel + { + /// + /// Gets the type of the current thread channel. + /// + ThreadType Type { get; } + + /// + /// Gets whether or not the current user has joined this thread. + /// + bool HasJoined { get; } + + /// + /// Gets whether or not the current thread is archived. + /// + bool IsArchived { get; } + + /// + /// Gets the duration of time before the thread is automatically archived after no activity. + /// + ThreadArchiveDuration AutoArchiveDuration { get; } + + /// + /// Gets the timestamp when the thread's archive status was last changed, used for calculating recent activity. + /// + DateTimeOffset ArchiveTimestamp { get; } + + /// + /// Gets whether or not the current thread is locked. + /// + bool IsLocked { get; } + + /// + /// Gets an approximate count of users in a thread, stops counting after 50. + /// + int MemberCount { get; } + + /// + /// Gets an approximate count of messages in a thread, stops counting after 50. + /// + int MessageCount { get; } + + /// + /// Joins the current thread. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous join operation. + /// + Task JoinAsync(RequestOptions options = null); + + /// + /// Leaves the current thread. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous leave operation. + /// + Task LeaveAsync(RequestOptions options = null); + + /// + /// Adds a user to this thread. + /// + /// The to add. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous operation of adding a member to a thread. + /// + Task AddUserAsync(IGuildUser user, RequestOptions options = null); + + /// + /// Removes a user from this thread. + /// + /// The to remove from this thread. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous operation of removing a user from this thread. + /// + Task RemoveUserAsync(IGuildUser user, RequestOptions options = null); + } +} diff --git a/src/Discord.Net.Core/Entities/Channels/StageInstanceProperties.cs b/src/Discord.Net.Core/Entities/Channels/StageInstanceProperties.cs new file mode 100644 index 000000000..35201fe0f --- /dev/null +++ b/src/Discord.Net.Core/Entities/Channels/StageInstanceProperties.cs @@ -0,0 +1,18 @@ +namespace Discord +{ + /// + /// Represents properties to use when modifying a stage instance. + /// + public class StageInstanceProperties + { + /// + /// Gets or sets the topic of the stage. + /// + public Optional Topic { get; set; } + + /// + /// Gets or sets the privacy level of the stage. + /// + public Optional PrivacyLevel { get; set; } + } +} diff --git a/src/Discord.Net.Core/Entities/Channels/StagePrivacyLevel.cs b/src/Discord.Net.Core/Entities/Channels/StagePrivacyLevel.cs new file mode 100644 index 000000000..0582a3e52 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Channels/StagePrivacyLevel.cs @@ -0,0 +1,17 @@ +namespace Discord +{ + /// + /// Represents the privacy level of a stage. + /// + public enum StagePrivacyLevel + { + /// + /// The Stage instance is visible publicly, such as on Stage Discovery. + /// + Public = 1, + /// + /// The Stage instance is visible to only guild members. + /// + GuildOnly = 2 + } +} diff --git a/src/Discord.Net.Core/Entities/Channels/TextChannelProperties.cs b/src/Discord.Net.Core/Entities/Channels/TextChannelProperties.cs index 821f358f5..2dceb025c 100644 --- a/src/Discord.Net.Core/Entities/Channels/TextChannelProperties.cs +++ b/src/Discord.Net.Core/Entities/Channels/TextChannelProperties.cs @@ -38,5 +38,21 @@ public class TextChannelProperties : GuildChannelProperties /// /// Thrown if the value does not fall within [0, 21600]. public Optional SlowModeInterval { get; set; } + + /// + /// Gets or sets whether or not the thread is archived. + /// + public Optional Archived { get; set; } + + /// + /// Gets or sets whether or not the thread is locked. + /// + public Optional Locked { get; set; } + + /// + /// Gets or sets the auto archive duration. + /// + public Optional AutoArchiveDuration { get; set; } + } } diff --git a/src/Discord.Net.Core/Entities/Channels/ThreadArchiveDuration.cs b/src/Discord.Net.Core/Entities/Channels/ThreadArchiveDuration.cs new file mode 100644 index 000000000..2c8a0652c --- /dev/null +++ b/src/Discord.Net.Core/Entities/Channels/ThreadArchiveDuration.cs @@ -0,0 +1,34 @@ +namespace Discord +{ + /// + /// Represents the thread auto archive duration. + /// + public enum ThreadArchiveDuration + { + /// + /// One hour (60 minutes). + /// + OneHour = 60, + + /// + /// One day (1440 minutes). + /// + OneDay = 1440, + + /// + /// Three days (4320 minutes). + /// + /// This option is explicitly available to nitro users. + /// + /// + ThreeDays = 4320, + + /// + /// One week (10080 minutes). + /// + /// This option is explicitly available to nitro users. + /// + /// + OneWeek = 10080 + } +} diff --git a/src/Discord.Net.Core/Entities/Channels/ThreadType.cs b/src/Discord.Net.Core/Entities/Channels/ThreadType.cs new file mode 100644 index 000000000..379128d21 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Channels/ThreadType.cs @@ -0,0 +1,23 @@ +namespace Discord +{ + /// + /// Represents types of threads. + /// + public enum ThreadType + { + /// + /// Represents a temporary sub-channel within a GUILD_NEWS channel. + /// + NewsThread = 10, + + /// + /// Represents a temporary sub-channel within a GUILD_TEXT channel. + /// + PublicThread = 11, + + /// + /// Represents a temporary sub-channel within a GUILD_TEXT channel that is only viewable by those invited and those with the MANAGE_THREADS permission + /// + PrivateThread = 12 + } +} diff --git a/src/Discord.Net.Core/Entities/Channels/VoiceChannelProperties.cs b/src/Discord.Net.Core/Entities/Channels/VoiceChannelProperties.cs index fb4d47800..251a45c3d 100644 --- a/src/Discord.Net.Core/Entities/Channels/VoiceChannelProperties.cs +++ b/src/Discord.Net.Core/Entities/Channels/VoiceChannelProperties.cs @@ -13,5 +13,9 @@ public class VoiceChannelProperties : GuildChannelProperties /// Gets or sets the maximum number of users that can be present in a channel, or null if none. /// public Optional UserLimit { get; set; } + /// + /// Gets or sets the channel voice region id, automatic when set to . + /// + public Optional RTCRegion { get; set; } } } diff --git a/src/Discord.Net.Core/Entities/Emotes/Emoji.cs b/src/Discord.Net.Core/Entities/Emotes/Emoji.cs index d5e795094..15c20148e 100644 --- a/src/Discord.Net.Core/Entities/Emotes/Emoji.cs +++ b/src/Discord.Net.Core/Entities/Emotes/Emoji.cs @@ -1,3 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Collections.ObjectModel; +using System.Linq; + namespace Discord { /// @@ -5,12 +11,11 @@ namespace Discord /// public class Emoji : IEmote { - // TODO: need to constrain this to Unicode-only emojis somehow - /// public string Name { get; } + /// - /// Gets the Unicode representation of this emote. + /// Gets the Unicode representation of this emoji. /// /// /// A string that resolves to . @@ -32,16 +37,5940 @@ public Emoji(string unicode) /// The object to compare with the current object. public override bool Equals(object other) { - if (other == null) return false; - if (other == this) return true; + if (other == null) + return false; + + if (other == this) + return true; + + return other is Emoji otherEmoji && string.Equals(Name, otherEmoji.Name); + } + + /// Tries to parse an from its raw format. + /// The raw encoding of an emoji. For example: :heart: or ❤ + /// An emoji. + public static bool TryParse(string text, out Emoji result) + { + result = null; + if (string.IsNullOrWhiteSpace(text)) + return false; + + if (NamesAndUnicodes.ContainsKey(text)) + result = new Emoji(NamesAndUnicodes[text]); + + if (Unicodes.Contains(text)) + result = new Emoji(text); + + return result != null; + } - var otherEmoji = other as Emoji; - if (otherEmoji == null) return false; + /// Parse an from its raw format. + /// The raw encoding of an emoji. For example: :heart: or ❤ + /// String is not emoji or unicode! + public static Emoji Parse(string emojiStr) + { + if (!TryParse(emojiStr, out var emoji)) + throw new FormatException("String is not emoji name or unicode!"); - return string.Equals(Name, otherEmoji.Name); + return emoji; } /// public override int GetHashCode() => Name.GetHashCode(); + + private static IReadOnlyDictionary NamesAndUnicodes { get; } = new Dictionary + { + [",:("] = "\uD83D\uDE13", + [",:)"] = "\uD83D\uDE05", + [",:-("] = "\uD83D\uDE13", + [",:-)"] = "\uD83D\uDE05", + [",=("] = "\uD83D\uDE13", + [",=)"] = "\uD83D\uDE05", + [",=-("] = "\uD83D\uDE13", + [",=-)"] = "\uD83D\uDE05", + ["0:)"] = "\uD83D\uDE07", + ["0:-)"] = "\uD83D\uDE07", + ["0=)"] = "\uD83D\uDE07", + ["0=-)"] = "\uD83D\uDE07", + ["8-)"] = "\uD83D\uDE0E", + [":$"] = "\uD83D\uDE12", + [":'("] = "\uD83D\uDE22", + [":')"] = "\uD83D\uDE02", + [":'-("] = "\uD83D\uDE22", + [":'-)"] = "\uD83D\uDE02", + [":'-D"] = "\uD83D\uDE02", + [":'D"] = "\uD83D\uDE02", + [":("] = "\uD83D\uDE26", + [":)"] = "\uD83D\uDE42", + [":*"] = "\uD83D\uDE17", + [":+1:"] = "\uD83D\uDC4D", + [":+1::skin-tone-1:"] = "\uD83D\uDC4D\uD83C\uDFFB", + [":+1::skin-tone-2:"] = "\uD83D\uDC4D\uD83C\uDFFC", + [":+1::skin-tone-3:"] = "\uD83D\uDC4D\uD83C\uDFFD", + [":+1::skin-tone-4:"] = "\uD83D\uDC4D\uD83C\uDFFE", + [":+1::skin-tone-5:"] = "\uD83D\uDC4D\uD83C\uDFFF", + [":+1_tone1:"] = "\uD83D\uDC4D\uD83C\uDFFB", + [":+1_tone2:"] = "\uD83D\uDC4D\uD83C\uDFFC", + [":+1_tone3:"] = "\uD83D\uDC4D\uD83C\uDFFD", + [":+1_tone4:"] = "\uD83D\uDC4D\uD83C\uDFFE", + [":+1_tone5:"] = "\uD83D\uDC4D\uD83C\uDFFF", + [":,'("] = "\uD83D\uDE2D", + [":,'-("] = "\uD83D\uDE2D", + [":,("] = "\uD83D\uDE22", + [":,)"] = "\uD83D\uDE02", + [":,-("] = "\uD83D\uDE22", + [":,-)"] = "\uD83D\uDE02", + [":,-D"] = "\uD83D\uDE02", + [":,D"] = "\uD83D\uDE02", + [":-$"] = "\uD83D\uDE12", + [":-("] = "\uD83D\uDE26", + [":-)"] = "\uD83D\uDE42", + [":-*"] = "\uD83D\uDE17", + [":-/"] = "\uD83D\uDE15", + [":-1:"] = "\uD83D\uDC4E", + [":-1::skin-tone-1:"] = "\uD83D\uDC4E\uD83C\uDFFB", + [":-1::skin-tone-2:"] = "\uD83D\uDC4E\uD83C\uDFFC", + [":-1::skin-tone-3:"] = "\uD83D\uDC4E\uD83C\uDFFD", + [":-1::skin-tone-4:"] = "\uD83D\uDC4E\uD83C\uDFFE", + [":-1::skin-tone-5:"] = "\uD83D\uDC4E\uD83C\uDFFF", + [":-@"] = "\uD83D\uDE21", + [":-D"] = "\uD83D\uDE04", + [":-O"] = "\uD83D\uDE2E", + [":-P"] = "\uD83D\uDE1B", + [":-S"] = "\uD83D\uDE12", + [":-Z"] = "\uD83D\uDE12", + [":-\")"] = "\uD83D\uDE0A", + [":-\\"] = "\uD83D\uDE15", + [":-o"] = "\uD83D\uDE2E", + [":-|"] = "\uD83D\uDE10", + [":100:"] = "\uD83D\uDCAF", + [":1234:"] = "\uD83D\uDD22", + [":8ball:"] = "\uD83C\uDFB1", + [":@"] = "\uD83D\uDE21", + [":D"] = "\uD83D\uDE04", + [":O"] = "\uD83D\uDE2E", + [":P"] = "\uD83D\uDE1B", + [":\")"] = "\uD83D\uDE0A", + [":_1_tone1:"] = "\uD83D\uDC4E\uD83C\uDFFB", + [":_1_tone2:"] = "\uD83D\uDC4E\uD83C\uDFFC", + [":_1_tone3:"] = "\uD83D\uDC4E\uD83C\uDFFD", + [":_1_tone4:"] = "\uD83D\uDC4E\uD83C\uDFFE", + [":_1_tone5:"] = "\uD83D\uDC4E\uD83C\uDFFF", + [":a:"] = "\uD83C\uDD70️", + [":ab:"] = "\uD83C\uDD8E", + [":abacus:"] = "\uD83E\uDDEE", + [":abc:"] = "\uD83D\uDD24", + [":abcd:"] = "\uD83D\uDD21", + [":accept:"] = "\uD83C\uDE51", + [":adhesive_bandage:"] = "\uD83E\uDE79", + [":admission_tickets:"] = "\uD83C\uDF9F️", + [":adult:"] = "\uD83E\uDDD1", + [":adult::skin-tone-1:"] = "\uD83E\uDDD1\uD83C\uDFFB", + [":adult::skin-tone-2:"] = "\uD83E\uDDD1\uD83C\uDFFC", + [":adult::skin-tone-3:"] = "\uD83E\uDDD1\uD83C\uDFFD", + [":adult::skin-tone-4:"] = "\uD83E\uDDD1\uD83C\uDFFE", + [":adult::skin-tone-5:"] = "\uD83E\uDDD1\uD83C\uDFFF", + [":adult_dark_skin_tone:"] = "\uD83E\uDDD1\uD83C\uDFFF", + [":adult_light_skin_tone:"] = "\uD83E\uDDD1\uD83C\uDFFB", + [":adult_medium_dark_skin_tone:"] = "\uD83E\uDDD1\uD83C\uDFFE", + [":adult_medium_light_skin_tone:"] = "\uD83E\uDDD1\uD83C\uDFFC", + [":adult_medium_skin_tone:"] = "\uD83E\uDDD1\uD83C\uDFFD", + [":adult_tone1:"] = "\uD83E\uDDD1\uD83C\uDFFB", + [":adult_tone2:"] = "\uD83E\uDDD1\uD83C\uDFFC", + [":adult_tone3:"] = "\uD83E\uDDD1\uD83C\uDFFD", + [":adult_tone4:"] = "\uD83E\uDDD1\uD83C\uDFFE", + [":adult_tone5:"] = "\uD83E\uDDD1\uD83C\uDFFF", + [":aerial_tramway:"] = "\uD83D\uDEA1", + [":airplane:"] = "✈️", + [":airplane_arriving:"] = "\uD83D\uDEEC", + [":airplane_departure:"] = "\uD83D\uDEEB", + [":airplane_small:"] = "\uD83D\uDEE9️", + [":alarm_clock:"] = "⏰", + [":alembic:"] = "⚗️", + [":alien:"] = "\uD83D\uDC7D", + [":ambulance:"] = "\uD83D\uDE91", + [":amphora:"] = "\uD83C\uDFFA", + [":anchor:"] = "⚓", + [":angel:"] = "\uD83D\uDC7C", + [":angel::skin-tone-1:"] = "\uD83D\uDC7C\uD83C\uDFFB", + [":angel::skin-tone-2:"] = "\uD83D\uDC7C\uD83C\uDFFC", + [":angel::skin-tone-3:"] = "\uD83D\uDC7C\uD83C\uDFFD", + [":angel::skin-tone-4:"] = "\uD83D\uDC7C\uD83C\uDFFE", + [":angel::skin-tone-5:"] = "\uD83D\uDC7C\uD83C\uDFFF", + [":angel_tone1:"] = "\uD83D\uDC7C\uD83C\uDFFB", + [":angel_tone2:"] = "\uD83D\uDC7C\uD83C\uDFFC", + [":angel_tone3:"] = "\uD83D\uDC7C\uD83C\uDFFD", + [":angel_tone4:"] = "\uD83D\uDC7C\uD83C\uDFFE", + [":angel_tone5:"] = "\uD83D\uDC7C\uD83C\uDFFF", + [":anger:"] = "\uD83D\uDCA2", + [":anger_right:"] = "\uD83D\uDDEF️", + [":angry:"] = "\uD83D\uDE20", + [":anguished:"] = "\uD83D\uDE27", + [":ant:"] = "\uD83D\uDC1C", + [":apple:"] = "\uD83C\uDF4E", + [":aquarius:"] = "♒", + [":archery:"] = "\uD83C\uDFF9", + [":aries:"] = "♈", + [":arrow_backward:"] = "◀️", + [":arrow_double_down:"] = "⏬", + [":arrow_double_up:"] = "⏫", + [":arrow_down:"] = "⬇️", + [":arrow_down_small:"] = "\uD83D\uDD3D", + [":arrow_forward:"] = "▶️", + [":arrow_heading_down:"] = "⤵️", + [":arrow_heading_up:"] = "⤴️", + [":arrow_left:"] = "⬅️", + [":arrow_lower_left:"] = "↙️", + [":arrow_lower_right:"] = "↘️", + [":arrow_right:"] = "➡️", + [":arrow_right_hook:"] = "↪️", + [":arrow_up:"] = "⬆️", + [":arrow_up_down:"] = "↕️", + [":arrow_up_small:"] = "\uD83D\uDD3C", + [":arrow_upper_left:"] = "↖️", + [":arrow_upper_right:"] = "↗️", + [":arrows_clockwise:"] = "\uD83D\uDD03", + [":arrows_counterclockwise:"] = "\uD83D\uDD04", + [":art:"] = "\uD83C\uDFA8", + [":articulated_lorry:"] = "\uD83D\uDE9B", + [":asterisk:"] = "*️⃣", + [":astonished:"] = "\uD83D\uDE32", + [":athletic_shoe:"] = "\uD83D\uDC5F", + [":atm:"] = "\uD83C\uDFE7", + [":atom:"] = "⚛️", + [":atom_symbol:"] = "⚛️", + [":auto_rickshaw:"] = "\uD83D\uDEFA", + [":avocado:"] = "\uD83E\uDD51", + [":axe:"] = "\uD83E\uDE93", + [":b:"] = "\uD83C\uDD71️", + [":baby:"] = "\uD83D\uDC76", + [":baby::skin-tone-1:"] = "\uD83D\uDC76\uD83C\uDFFB", + [":baby::skin-tone-2:"] = "\uD83D\uDC76\uD83C\uDFFC", + [":baby::skin-tone-3:"] = "\uD83D\uDC76\uD83C\uDFFD", + [":baby::skin-tone-4:"] = "\uD83D\uDC76\uD83C\uDFFE", + [":baby::skin-tone-5:"] = "\uD83D\uDC76\uD83C\uDFFF", + [":baby_bottle:"] = "\uD83C\uDF7C", + [":baby_chick:"] = "\uD83D\uDC24", + [":baby_symbol:"] = "\uD83D\uDEBC", + [":baby_tone1:"] = "\uD83D\uDC76\uD83C\uDFFB", + [":baby_tone2:"] = "\uD83D\uDC76\uD83C\uDFFC", + [":baby_tone3:"] = "\uD83D\uDC76\uD83C\uDFFD", + [":baby_tone4:"] = "\uD83D\uDC76\uD83C\uDFFE", + [":baby_tone5:"] = "\uD83D\uDC76\uD83C\uDFFF", + [":back:"] = "\uD83D\uDD19", + [":back_of_hand:"] = "\uD83E\uDD1A", + [":back_of_hand::skin-tone-1:"] = "\uD83E\uDD1A\uD83C\uDFFB", + [":back_of_hand::skin-tone-2:"] = "\uD83E\uDD1A\uD83C\uDFFC", + [":back_of_hand::skin-tone-3:"] = "\uD83E\uDD1A\uD83C\uDFFD", + [":back_of_hand::skin-tone-4:"] = "\uD83E\uDD1A\uD83C\uDFFE", + [":back_of_hand::skin-tone-5:"] = "\uD83E\uDD1A\uD83C\uDFFF", + [":back_of_hand_tone1:"] = "\uD83E\uDD1A\uD83C\uDFFB", + [":back_of_hand_tone2:"] = "\uD83E\uDD1A\uD83C\uDFFC", + [":back_of_hand_tone3:"] = "\uD83E\uDD1A\uD83C\uDFFD", + [":back_of_hand_tone4:"] = "\uD83E\uDD1A\uD83C\uDFFE", + [":back_of_hand_tone5:"] = "\uD83E\uDD1A\uD83C\uDFFF", + [":bacon:"] = "\uD83E\uDD53", + [":badger:"] = "\uD83E\uDDA1", + [":badminton:"] = "\uD83C\uDFF8", + [":bagel:"] = "\uD83E\uDD6F", + [":baggage_claim:"] = "\uD83D\uDEC4", + [":baguette_bread:"] = "\uD83E\uDD56", + [":ballet_shoes:"] = "\uD83E\uDE70", + [":balloon:"] = "\uD83C\uDF88", + [":ballot_box:"] = "\uD83D\uDDF3️", + [":ballot_box_with_ballot:"] = "\uD83D\uDDF3️", + [":ballot_box_with_check:"] = "☑️", + [":bamboo:"] = "\uD83C\uDF8D", + [":banana:"] = "\uD83C\uDF4C", + [":bangbang:"] = "‼️", + [":banjo:"] = "\uD83E\uDE95", + [":bank:"] = "\uD83C\uDFE6", + [":bar_chart:"] = "\uD83D\uDCCA", + [":barber:"] = "\uD83D\uDC88", + [":baseball:"] = "⚾", + [":basket:"] = "\uD83E\uDDFA", + [":basketball:"] = "\uD83C\uDFC0", + [":basketball_player:"] = "⛹️", + [":basketball_player::skin-tone-1:"] = "⛹\uD83C\uDFFB", + [":basketball_player::skin-tone-2:"] = "⛹\uD83C\uDFFC", + [":basketball_player::skin-tone-3:"] = "⛹\uD83C\uDFFD", + [":basketball_player::skin-tone-4:"] = "⛹\uD83C\uDFFE", + [":basketball_player::skin-tone-5:"] = "⛹\uD83C\uDFFF", + [":basketball_player_tone1:"] = "⛹\uD83C\uDFFB", + [":basketball_player_tone2:"] = "⛹\uD83C\uDFFC", + [":basketball_player_tone3:"] = "⛹\uD83C\uDFFD", + [":basketball_player_tone4:"] = "⛹\uD83C\uDFFE", + [":basketball_player_tone5:"] = "⛹\uD83C\uDFFF", + [":bat:"] = "\uD83E\uDD87", + [":bath:"] = "\uD83D\uDEC0", + [":bath::skin-tone-1:"] = "\uD83D\uDEC0\uD83C\uDFFB", + [":bath::skin-tone-2:"] = "\uD83D\uDEC0\uD83C\uDFFC", + [":bath::skin-tone-3:"] = "\uD83D\uDEC0\uD83C\uDFFD", + [":bath::skin-tone-4:"] = "\uD83D\uDEC0\uD83C\uDFFE", + [":bath::skin-tone-5:"] = "\uD83D\uDEC0\uD83C\uDFFF", + [":bath_tone1:"] = "\uD83D\uDEC0\uD83C\uDFFB", + [":bath_tone2:"] = "\uD83D\uDEC0\uD83C\uDFFC", + [":bath_tone3:"] = "\uD83D\uDEC0\uD83C\uDFFD", + [":bath_tone4:"] = "\uD83D\uDEC0\uD83C\uDFFE", + [":bath_tone5:"] = "\uD83D\uDEC0\uD83C\uDFFF", + [":bathtub:"] = "\uD83D\uDEC1", + [":battery:"] = "\uD83D\uDD0B", + [":beach:"] = "\uD83C\uDFD6️", + [":beach_umbrella:"] = "⛱️", + [":beach_with_umbrella:"] = "\uD83C\uDFD6️", + [":bear:"] = "\uD83D\uDC3B", + [":bearded_person:"] = "\uD83E\uDDD4", + [":bearded_person::skin-tone-1:"] = "\uD83E\uDDD4\uD83C\uDFFB", + [":bearded_person::skin-tone-2:"] = "\uD83E\uDDD4\uD83C\uDFFC", + [":bearded_person::skin-tone-3:"] = "\uD83E\uDDD4\uD83C\uDFFD", + [":bearded_person::skin-tone-4:"] = "\uD83E\uDDD4\uD83C\uDFFE", + [":bearded_person::skin-tone-5:"] = "\uD83E\uDDD4\uD83C\uDFFF", + [":bearded_person_dark_skin_tone:"] = "\uD83E\uDDD4\uD83C\uDFFF", + [":bearded_person_light_skin_tone:"] = "\uD83E\uDDD4\uD83C\uDFFB", + [":bearded_person_medium_dark_skin_tone:"] = "\uD83E\uDDD4\uD83C\uDFFE", + [":bearded_person_medium_light_skin_tone:"] = "\uD83E\uDDD4\uD83C\uDFFC", + [":bearded_person_medium_skin_tone:"] = "\uD83E\uDDD4\uD83C\uDFFD", + [":bearded_person_tone1:"] = "\uD83E\uDDD4\uD83C\uDFFB", + [":bearded_person_tone2:"] = "\uD83E\uDDD4\uD83C\uDFFC", + [":bearded_person_tone3:"] = "\uD83E\uDDD4\uD83C\uDFFD", + [":bearded_person_tone4:"] = "\uD83E\uDDD4\uD83C\uDFFE", + [":bearded_person_tone5:"] = "\uD83E\uDDD4\uD83C\uDFFF", + [":bed:"] = "\uD83D\uDECF️", + [":bee:"] = "\uD83D\uDC1D", + [":beer:"] = "\uD83C\uDF7A", + [":beers:"] = "\uD83C\uDF7B", + [":beetle:"] = "\uD83D\uDC1E", + [":beginner:"] = "\uD83D\uDD30", + [":bell:"] = "\uD83D\uDD14", + [":bellhop:"] = "\uD83D\uDECE️", + [":bellhop_bell:"] = "\uD83D\uDECE️", + [":bento:"] = "\uD83C\uDF71", + [":beverage_box:"] = "\uD83E\uDDC3", + [":bicyclist:"] = "\uD83D\uDEB4", + [":bicyclist::skin-tone-1:"] = "\uD83D\uDEB4\uD83C\uDFFB", + [":bicyclist::skin-tone-2:"] = "\uD83D\uDEB4\uD83C\uDFFC", + [":bicyclist::skin-tone-3:"] = "\uD83D\uDEB4\uD83C\uDFFD", + [":bicyclist::skin-tone-4:"] = "\uD83D\uDEB4\uD83C\uDFFE", + [":bicyclist::skin-tone-5:"] = "\uD83D\uDEB4\uD83C\uDFFF", + [":bicyclist_tone1:"] = "\uD83D\uDEB4\uD83C\uDFFB", + [":bicyclist_tone2:"] = "\uD83D\uDEB4\uD83C\uDFFC", + [":bicyclist_tone3:"] = "\uD83D\uDEB4\uD83C\uDFFD", + [":bicyclist_tone4:"] = "\uD83D\uDEB4\uD83C\uDFFE", + [":bicyclist_tone5:"] = "\uD83D\uDEB4\uD83C\uDFFF", + [":bike:"] = "\uD83D\uDEB2", + [":bikini:"] = "\uD83D\uDC59", + [":billed_cap:"] = "\uD83E\uDDE2", + [":biohazard:"] = "☣️", + [":biohazard_sign:"] = "☣️", + [":bird:"] = "\uD83D\uDC26", + [":birthday:"] = "\uD83C\uDF82", + [":black_circle:"] = "⚫", + [":black_heart:"] = "\uD83D\uDDA4", + [":black_joker:"] = "\uD83C\uDCCF", + [":black_large_square:"] = "⬛", + [":black_medium_small_square:"] = "◾", + [":black_medium_square:"] = "◼️", + [":black_nib:"] = "✒️", + [":black_small_square:"] = "▪️", + [":black_square_button:"] = "\uD83D\uDD32", + [":blond_haired_man:"] = "\uD83D\uDC71\u200D♂️", + [":blond_haired_man::skin-tone-1:"] = "\uD83D\uDC71\uD83C\uDFFB\u200D♂️", + [":blond_haired_man::skin-tone-2:"] = "\uD83D\uDC71\uD83C\uDFFC\u200D♂️", + [":blond_haired_man::skin-tone-3:"] = "\uD83D\uDC71\uD83C\uDFFD\u200D♂️", + [":blond_haired_man::skin-tone-4:"] = "\uD83D\uDC71\uD83C\uDFFE\u200D♂️", + [":blond_haired_man::skin-tone-5:"] = "\uD83D\uDC71\uD83C\uDFFF\u200D♂️", + [":blond_haired_man_dark_skin_tone:"] = "\uD83D\uDC71\uD83C\uDFFF\u200D♂️", + [":blond_haired_man_light_skin_tone:"] = "\uD83D\uDC71\uD83C\uDFFB\u200D♂️", + [":blond_haired_man_medium_dark_skin_tone:"] = "\uD83D\uDC71\uD83C\uDFFE\u200D♂️", + [":blond_haired_man_medium_light_skin_tone:"] = "\uD83D\uDC71\uD83C\uDFFC\u200D♂️", + [":blond_haired_man_medium_skin_tone:"] = "\uD83D\uDC71\uD83C\uDFFD\u200D♂️", + [":blond_haired_man_tone1:"] = "\uD83D\uDC71\uD83C\uDFFB\u200D♂️", + [":blond_haired_man_tone2:"] = "\uD83D\uDC71\uD83C\uDFFC\u200D♂️", + [":blond_haired_man_tone3:"] = "\uD83D\uDC71\uD83C\uDFFD\u200D♂️", + [":blond_haired_man_tone4:"] = "\uD83D\uDC71\uD83C\uDFFE\u200D♂️", + [":blond_haired_man_tone5:"] = "\uD83D\uDC71\uD83C\uDFFF\u200D♂️", + [":blond_haired_person:"] = "\uD83D\uDC71", + [":blond_haired_person::skin-tone-1:"] = "\uD83D\uDC71\uD83C\uDFFB", + [":blond_haired_person::skin-tone-2:"] = "\uD83D\uDC71\uD83C\uDFFC", + [":blond_haired_person::skin-tone-3:"] = "\uD83D\uDC71\uD83C\uDFFD", + [":blond_haired_person::skin-tone-4:"] = "\uD83D\uDC71\uD83C\uDFFE", + [":blond_haired_person::skin-tone-5:"] = "\uD83D\uDC71\uD83C\uDFFF", + [":blond_haired_person_tone1:"] = "\uD83D\uDC71\uD83C\uDFFB", + [":blond_haired_person_tone2:"] = "\uD83D\uDC71\uD83C\uDFFC", + [":blond_haired_person_tone3:"] = "\uD83D\uDC71\uD83C\uDFFD", + [":blond_haired_person_tone4:"] = "\uD83D\uDC71\uD83C\uDFFE", + [":blond_haired_person_tone5:"] = "\uD83D\uDC71\uD83C\uDFFF", + [":blond_haired_woman:"] = "\uD83D\uDC71\u200D♀️", + [":blond_haired_woman::skin-tone-1:"] = "\uD83D\uDC71\uD83C\uDFFB\u200D♀️", + [":blond_haired_woman::skin-tone-2:"] = "\uD83D\uDC71\uD83C\uDFFC\u200D♀️", + [":blond_haired_woman::skin-tone-3:"] = "\uD83D\uDC71\uD83C\uDFFD\u200D♀️", + [":blond_haired_woman::skin-tone-4:"] = "\uD83D\uDC71\uD83C\uDFFE\u200D♀️", + [":blond_haired_woman::skin-tone-5:"] = "\uD83D\uDC71\uD83C\uDFFF\u200D♀️", + [":blond_haired_woman_dark_skin_tone:"] = "\uD83D\uDC71\uD83C\uDFFF\u200D♀️", + [":blond_haired_woman_light_skin_tone:"] = "\uD83D\uDC71\uD83C\uDFFB\u200D♀️", + [":blond_haired_woman_medium_dark_skin_tone:"] = "\uD83D\uDC71\uD83C\uDFFE\u200D♀️", + [":blond_haired_woman_medium_light_skin_tone:"] = "\uD83D\uDC71\uD83C\uDFFC\u200D♀️", + [":blond_haired_woman_medium_skin_tone:"] = "\uD83D\uDC71\uD83C\uDFFD\u200D♀️", + [":blond_haired_woman_tone1:"] = "\uD83D\uDC71\uD83C\uDFFB\u200D♀️", + [":blond_haired_woman_tone2:"] = "\uD83D\uDC71\uD83C\uDFFC\u200D♀️", + [":blond_haired_woman_tone3:"] = "\uD83D\uDC71\uD83C\uDFFD\u200D♀️", + [":blond_haired_woman_tone4:"] = "\uD83D\uDC71\uD83C\uDFFE\u200D♀️", + [":blond_haired_woman_tone5:"] = "\uD83D\uDC71\uD83C\uDFFF\u200D♀️", + [":blossom:"] = "\uD83C\uDF3C", + [":blowfish:"] = "\uD83D\uDC21", + [":blue_book:"] = "\uD83D\uDCD8", + [":blue_car:"] = "\uD83D\uDE99", + [":blue_circle:"] = "\uD83D\uDD35", + [":blue_heart:"] = "\uD83D\uDC99", + [":blue_square:"] = "\uD83D\uDFE6", + [":blush:"] = "\uD83D\uDE0A", + [":boar:"] = "\uD83D\uDC17", + [":bomb:"] = "\uD83D\uDCA3", + [":bone:"] = "\uD83E\uDDB4", + [":book:"] = "\uD83D\uDCD6", + [":bookmark:"] = "\uD83D\uDD16", + [":bookmark_tabs:"] = "\uD83D\uDCD1", + [":books:"] = "\uD83D\uDCDA", + [":boom:"] = "\uD83D\uDCA5", + [":boot:"] = "\uD83D\uDC62", + [":bottle_with_popping_cork:"] = "\uD83C\uDF7E", + [":bouquet:"] = "\uD83D\uDC90", + [":bow:"] = "\uD83D\uDE47", + [":bow::skin-tone-1:"] = "\uD83D\uDE47\uD83C\uDFFB", + [":bow::skin-tone-2:"] = "\uD83D\uDE47\uD83C\uDFFC", + [":bow::skin-tone-3:"] = "\uD83D\uDE47\uD83C\uDFFD", + [":bow::skin-tone-4:"] = "\uD83D\uDE47\uD83C\uDFFE", + [":bow::skin-tone-5:"] = "\uD83D\uDE47\uD83C\uDFFF", + [":bow_and_arrow:"] = "\uD83C\uDFF9", + [":bow_tone1:"] = "\uD83D\uDE47\uD83C\uDFFB", + [":bow_tone2:"] = "\uD83D\uDE47\uD83C\uDFFC", + [":bow_tone3:"] = "\uD83D\uDE47\uD83C\uDFFD", + [":bow_tone4:"] = "\uD83D\uDE47\uD83C\uDFFE", + [":bow_tone5:"] = "\uD83D\uDE47\uD83C\uDFFF", + [":bowl_with_spoon:"] = "\uD83E\uDD63", + [":bowling:"] = "\uD83C\uDFB3", + [":boxing_glove:"] = "\uD83E\uDD4A", + [":boxing_gloves:"] = "\uD83E\uDD4A", + [":boy:"] = "\uD83D\uDC66", + [":boy::skin-tone-1:"] = "\uD83D\uDC66\uD83C\uDFFB", + [":boy::skin-tone-2:"] = "\uD83D\uDC66\uD83C\uDFFC", + [":boy::skin-tone-3:"] = "\uD83D\uDC66\uD83C\uDFFD", + [":boy::skin-tone-4:"] = "\uD83D\uDC66\uD83C\uDFFE", + [":boy::skin-tone-5:"] = "\uD83D\uDC66\uD83C\uDFFF", + [":boy_tone1:"] = "\uD83D\uDC66\uD83C\uDFFB", + [":boy_tone2:"] = "\uD83D\uDC66\uD83C\uDFFC", + [":boy_tone3:"] = "\uD83D\uDC66\uD83C\uDFFD", + [":boy_tone4:"] = "\uD83D\uDC66\uD83C\uDFFE", + [":boy_tone5:"] = "\uD83D\uDC66\uD83C\uDFFF", + [":brain:"] = "\uD83E\uDDE0", + [":bread:"] = "\uD83C\uDF5E", + [":breast_feeding:"] = "\uD83E\uDD31", + [":breast_feeding::skin-tone-1:"] = "\uD83E\uDD31\uD83C\uDFFB", + [":breast_feeding::skin-tone-2:"] = "\uD83E\uDD31\uD83C\uDFFC", + [":breast_feeding::skin-tone-3:"] = "\uD83E\uDD31\uD83C\uDFFD", + [":breast_feeding::skin-tone-4:"] = "\uD83E\uDD31\uD83C\uDFFE", + [":breast_feeding::skin-tone-5:"] = "\uD83E\uDD31\uD83C\uDFFF", + [":breast_feeding_dark_skin_tone:"] = "\uD83E\uDD31\uD83C\uDFFF", + [":breast_feeding_light_skin_tone:"] = "\uD83E\uDD31\uD83C\uDFFB", + [":breast_feeding_medium_dark_skin_tone:"] = "\uD83E\uDD31\uD83C\uDFFE", + [":breast_feeding_medium_light_skin_tone:"] = "\uD83E\uDD31\uD83C\uDFFC", + [":breast_feeding_medium_skin_tone:"] = "\uD83E\uDD31\uD83C\uDFFD", + [":breast_feeding_tone1:"] = "\uD83E\uDD31\uD83C\uDFFB", + [":breast_feeding_tone2:"] = "\uD83E\uDD31\uD83C\uDFFC", + [":breast_feeding_tone3:"] = "\uD83E\uDD31\uD83C\uDFFD", + [":breast_feeding_tone4:"] = "\uD83E\uDD31\uD83C\uDFFE", + [":breast_feeding_tone5:"] = "\uD83E\uDD31\uD83C\uDFFF", + [":bricks:"] = "\uD83E\uDDF1", + [":bride_with_veil:"] = "\uD83D\uDC70", + [":bride_with_veil::skin-tone-1:"] = "\uD83D\uDC70\uD83C\uDFFB", + [":bride_with_veil::skin-tone-2:"] = "\uD83D\uDC70\uD83C\uDFFC", + [":bride_with_veil::skin-tone-3:"] = "\uD83D\uDC70\uD83C\uDFFD", + [":bride_with_veil::skin-tone-4:"] = "\uD83D\uDC70\uD83C\uDFFE", + [":bride_with_veil::skin-tone-5:"] = "\uD83D\uDC70\uD83C\uDFFF", + [":bride_with_veil_tone1:"] = "\uD83D\uDC70\uD83C\uDFFB", + [":bride_with_veil_tone2:"] = "\uD83D\uDC70\uD83C\uDFFC", + [":bride_with_veil_tone3:"] = "\uD83D\uDC70\uD83C\uDFFD", + [":bride_with_veil_tone4:"] = "\uD83D\uDC70\uD83C\uDFFE", + [":bride_with_veil_tone5:"] = "\uD83D\uDC70\uD83C\uDFFF", + [":bridge_at_night:"] = "\uD83C\uDF09", + [":briefcase:"] = "\uD83D\uDCBC", + [":briefs:"] = "\uD83E\uDE72", + [":broccoli:"] = "\uD83E\uDD66", + [":broken_heart:"] = "\uD83D\uDC94", + [":broom:"] = "\uD83E\uDDF9", + [":brown_circle:"] = "\uD83D\uDFE4", + [":brown_heart:"] = "\uD83E\uDD0E", + [":brown_square:"] = "\uD83D\uDFEB", + [":bug:"] = "\uD83D\uDC1B", + [":building_construction:"] = "\uD83C\uDFD7️", + [":bulb:"] = "\uD83D\uDCA1", + [":bullettrain_front:"] = "\uD83D\uDE85", + [":bullettrain_side:"] = "\uD83D\uDE84", + [":burrito:"] = "\uD83C\uDF2F", + [":bus:"] = "\uD83D\uDE8C", + [":busstop:"] = "\uD83D\uDE8F", + [":bust_in_silhouette:"] = "\uD83D\uDC64", + [":busts_in_silhouette:"] = "\uD83D\uDC65", + [":butter:"] = "\uD83E\uDDC8", + [":butterfly:"] = "\uD83E\uDD8B", + [":cactus:"] = "\uD83C\uDF35", + [":cake:"] = "\uD83C\uDF70", + [":calendar:"] = "\uD83D\uDCC6", + [":calendar_spiral:"] = "\uD83D\uDDD3️", + [":call_me:"] = "\uD83E\uDD19", + [":call_me::skin-tone-1:"] = "\uD83E\uDD19\uD83C\uDFFB", + [":call_me::skin-tone-2:"] = "\uD83E\uDD19\uD83C\uDFFC", + [":call_me::skin-tone-3:"] = "\uD83E\uDD19\uD83C\uDFFD", + [":call_me::skin-tone-4:"] = "\uD83E\uDD19\uD83C\uDFFE", + [":call_me::skin-tone-5:"] = "\uD83E\uDD19\uD83C\uDFFF", + [":call_me_hand:"] = "\uD83E\uDD19", + [":call_me_hand::skin-tone-1:"] = "\uD83E\uDD19\uD83C\uDFFB", + [":call_me_hand::skin-tone-2:"] = "\uD83E\uDD19\uD83C\uDFFC", + [":call_me_hand::skin-tone-3:"] = "\uD83E\uDD19\uD83C\uDFFD", + [":call_me_hand::skin-tone-4:"] = "\uD83E\uDD19\uD83C\uDFFE", + [":call_me_hand::skin-tone-5:"] = "\uD83E\uDD19\uD83C\uDFFF", + [":call_me_hand_tone1:"] = "\uD83E\uDD19\uD83C\uDFFB", + [":call_me_hand_tone2:"] = "\uD83E\uDD19\uD83C\uDFFC", + [":call_me_hand_tone3:"] = "\uD83E\uDD19\uD83C\uDFFD", + [":call_me_hand_tone4:"] = "\uD83E\uDD19\uD83C\uDFFE", + [":call_me_hand_tone5:"] = "\uD83E\uDD19\uD83C\uDFFF", + [":call_me_tone1:"] = "\uD83E\uDD19\uD83C\uDFFB", + [":call_me_tone2:"] = "\uD83E\uDD19\uD83C\uDFFC", + [":call_me_tone3:"] = "\uD83E\uDD19\uD83C\uDFFD", + [":call_me_tone4:"] = "\uD83E\uDD19\uD83C\uDFFE", + [":call_me_tone5:"] = "\uD83E\uDD19\uD83C\uDFFF", + [":calling:"] = "\uD83D\uDCF2", + [":camel:"] = "\uD83D\uDC2B", + [":camera:"] = "\uD83D\uDCF7", + [":camera_with_flash:"] = "\uD83D\uDCF8", + [":camping:"] = "\uD83C\uDFD5️", + [":cancer:"] = "♋", + [":candle:"] = "\uD83D\uDD6F️", + [":candy:"] = "\uD83C\uDF6C", + [":canned_food:"] = "\uD83E\uDD6B", + [":canoe:"] = "\uD83D\uDEF6", + [":capital_abcd:"] = "\uD83D\uDD20", + [":capricorn:"] = "♑", + [":card_box:"] = "\uD83D\uDDC3️", + [":card_file_box:"] = "\uD83D\uDDC3️", + [":card_index:"] = "\uD83D\uDCC7", + [":card_index_dividers:"] = "\uD83D\uDDC2️", + [":carousel_horse:"] = "\uD83C\uDFA0", + [":carrot:"] = "\uD83E\uDD55", + [":cartwheel:"] = "\uD83E\uDD38", + [":cartwheel::skin-tone-1:"] = "\uD83E\uDD38\uD83C\uDFFB", + [":cartwheel::skin-tone-2:"] = "\uD83E\uDD38\uD83C\uDFFC", + [":cartwheel::skin-tone-3:"] = "\uD83E\uDD38\uD83C\uDFFD", + [":cartwheel::skin-tone-4:"] = "\uD83E\uDD38\uD83C\uDFFE", + [":cartwheel::skin-tone-5:"] = "\uD83E\uDD38\uD83C\uDFFF", + [":cartwheel_tone1:"] = "\uD83E\uDD38\uD83C\uDFFB", + [":cartwheel_tone2:"] = "\uD83E\uDD38\uD83C\uDFFC", + [":cartwheel_tone3:"] = "\uD83E\uDD38\uD83C\uDFFD", + [":cartwheel_tone4:"] = "\uD83E\uDD38\uD83C\uDFFE", + [":cartwheel_tone5:"] = "\uD83E\uDD38\uD83C\uDFFF", + [":cat2:"] = "\uD83D\uDC08", + [":cat:"] = "\uD83D\uDC31", + [":cd:"] = "\uD83D\uDCBF", + [":chains:"] = "⛓️", + [":chair:"] = "\uD83E\uDE91", + [":champagne:"] = "\uD83C\uDF7E", + [":champagne_glass:"] = "\uD83E\uDD42", + [":chart:"] = "\uD83D\uDCB9", + [":chart_with_downwards_trend:"] = "\uD83D\uDCC9", + [":chart_with_upwards_trend:"] = "\uD83D\uDCC8", + [":checkered_flag:"] = "\uD83C\uDFC1", + [":cheese:"] = "\uD83E\uDDC0", + [":cheese_wedge:"] = "\uD83E\uDDC0", + [":cherries:"] = "\uD83C\uDF52", + [":cherry_blossom:"] = "\uD83C\uDF38", + [":chess_pawn:"] = "♟️", + [":chestnut:"] = "\uD83C\uDF30", + [":chicken:"] = "\uD83D\uDC14", + [":child:"] = "\uD83E\uDDD2", + [":child::skin-tone-1:"] = "\uD83E\uDDD2\uD83C\uDFFB", + [":child::skin-tone-2:"] = "\uD83E\uDDD2\uD83C\uDFFC", + [":child::skin-tone-3:"] = "\uD83E\uDDD2\uD83C\uDFFD", + [":child::skin-tone-4:"] = "\uD83E\uDDD2\uD83C\uDFFE", + [":child::skin-tone-5:"] = "\uD83E\uDDD2\uD83C\uDFFF", + [":child_dark_skin_tone:"] = "\uD83E\uDDD2\uD83C\uDFFF", + [":child_light_skin_tone:"] = "\uD83E\uDDD2\uD83C\uDFFB", + [":child_medium_dark_skin_tone:"] = "\uD83E\uDDD2\uD83C\uDFFE", + [":child_medium_light_skin_tone:"] = "\uD83E\uDDD2\uD83C\uDFFC", + [":child_medium_skin_tone:"] = "\uD83E\uDDD2\uD83C\uDFFD", + [":child_tone1:"] = "\uD83E\uDDD2\uD83C\uDFFB", + [":child_tone2:"] = "\uD83E\uDDD2\uD83C\uDFFC", + [":child_tone3:"] = "\uD83E\uDDD2\uD83C\uDFFD", + [":child_tone4:"] = "\uD83E\uDDD2\uD83C\uDFFE", + [":child_tone5:"] = "\uD83E\uDDD2\uD83C\uDFFF", + [":children_crossing:"] = "\uD83D\uDEB8", + [":chipmunk:"] = "\uD83D\uDC3F️", + [":chocolate_bar:"] = "\uD83C\uDF6B", + [":chopsticks:"] = "\uD83E\uDD62", + [":christmas_tree:"] = "\uD83C\uDF84", + [":church:"] = "⛪", + [":cinema:"] = "\uD83C\uDFA6", + [":circus_tent:"] = "\uD83C\uDFAA", + [":city_dusk:"] = "\uD83C\uDF06", + [":city_sunrise:"] = "\uD83C\uDF07", + [":city_sunset:"] = "\uD83C\uDF07", + [":cityscape:"] = "\uD83C\uDFD9️", + [":cl:"] = "\uD83C\uDD91", + [":clap:"] = "\uD83D\uDC4F", + [":clap::skin-tone-1:"] = "\uD83D\uDC4F\uD83C\uDFFB", + [":clap::skin-tone-2:"] = "\uD83D\uDC4F\uD83C\uDFFC", + [":clap::skin-tone-3:"] = "\uD83D\uDC4F\uD83C\uDFFD", + [":clap::skin-tone-4:"] = "\uD83D\uDC4F\uD83C\uDFFE", + [":clap::skin-tone-5:"] = "\uD83D\uDC4F\uD83C\uDFFF", + [":clap_tone1:"] = "\uD83D\uDC4F\uD83C\uDFFB", + [":clap_tone2:"] = "\uD83D\uDC4F\uD83C\uDFFC", + [":clap_tone3:"] = "\uD83D\uDC4F\uD83C\uDFFD", + [":clap_tone4:"] = "\uD83D\uDC4F\uD83C\uDFFE", + [":clap_tone5:"] = "\uD83D\uDC4F\uD83C\uDFFF", + [":clapper:"] = "\uD83C\uDFAC", + [":classical_building:"] = "\uD83C\uDFDB️", + [":clinking_glass:"] = "\uD83E\uDD42", + [":clipboard:"] = "\uD83D\uDCCB", + [":clock1030:"] = "\uD83D\uDD65", + [":clock10:"] = "\uD83D\uDD59", + [":clock1130:"] = "\uD83D\uDD66", + [":clock11:"] = "\uD83D\uDD5A", + [":clock1230:"] = "\uD83D\uDD67", + [":clock12:"] = "\uD83D\uDD5B", + [":clock130:"] = "\uD83D\uDD5C", + [":clock1:"] = "\uD83D\uDD50", + [":clock230:"] = "\uD83D\uDD5D", + [":clock2:"] = "\uD83D\uDD51", + [":clock330:"] = "\uD83D\uDD5E", + [":clock3:"] = "\uD83D\uDD52", + [":clock430:"] = "\uD83D\uDD5F", + [":clock4:"] = "\uD83D\uDD53", + [":clock530:"] = "\uD83D\uDD60", + [":clock5:"] = "\uD83D\uDD54", + [":clock630:"] = "\uD83D\uDD61", + [":clock6:"] = "\uD83D\uDD55", + [":clock730:"] = "\uD83D\uDD62", + [":clock7:"] = "\uD83D\uDD56", + [":clock830:"] = "\uD83D\uDD63", + [":clock8:"] = "\uD83D\uDD57", + [":clock930:"] = "\uD83D\uDD64", + [":clock9:"] = "\uD83D\uDD58", + [":clock:"] = "\uD83D\uDD70️", + [":closed_book:"] = "\uD83D\uDCD5", + [":closed_lock_with_key:"] = "\uD83D\uDD10", + [":closed_umbrella:"] = "\uD83C\uDF02", + [":cloud:"] = "☁️", + [":cloud_lightning:"] = "\uD83C\uDF29️", + [":cloud_rain:"] = "\uD83C\uDF27️", + [":cloud_snow:"] = "\uD83C\uDF28️", + [":cloud_tornado:"] = "\uD83C\uDF2A️", + [":cloud_with_lightning:"] = "\uD83C\uDF29️", + [":cloud_with_rain:"] = "\uD83C\uDF27️", + [":cloud_with_snow:"] = "\uD83C\uDF28️", + [":cloud_with_tornado:"] = "\uD83C\uDF2A️", + [":clown:"] = "\uD83E\uDD21", + [":clown_face:"] = "\uD83E\uDD21", + [":clubs:"] = "♣️", + [":coat:"] = "\uD83E\uDDE5", + [":cocktail:"] = "\uD83C\uDF78", + [":coconut:"] = "\uD83E\uDD65", + [":coffee:"] = "☕", + [":coffin:"] = "⚰️", + [":cold_face:"] = "\uD83E\uDD76", + [":cold_sweat:"] = "\uD83D\uDE30", + [":comet:"] = "☄️", + [":compass:"] = "\uD83E\uDDED", + [":compression:"] = "\uD83D\uDDDC️", + [":computer:"] = "\uD83D\uDCBB", + [":confetti_ball:"] = "\uD83C\uDF8A", + [":confounded:"] = "\uD83D\uDE16", + [":confused:"] = "\uD83D\uDE15", + [":congratulations:"] = "㊗️", + [":construction:"] = "\uD83D\uDEA7", + [":construction_site:"] = "\uD83C\uDFD7️", + [":construction_worker:"] = "\uD83D\uDC77", + [":construction_worker::skin-tone-1:"] = "\uD83D\uDC77\uD83C\uDFFB", + [":construction_worker::skin-tone-2:"] = "\uD83D\uDC77\uD83C\uDFFC", + [":construction_worker::skin-tone-3:"] = "\uD83D\uDC77\uD83C\uDFFD", + [":construction_worker::skin-tone-4:"] = "\uD83D\uDC77\uD83C\uDFFE", + [":construction_worker::skin-tone-5:"] = "\uD83D\uDC77\uD83C\uDFFF", + [":construction_worker_tone1:"] = "\uD83D\uDC77\uD83C\uDFFB", + [":construction_worker_tone2:"] = "\uD83D\uDC77\uD83C\uDFFC", + [":construction_worker_tone3:"] = "\uD83D\uDC77\uD83C\uDFFD", + [":construction_worker_tone4:"] = "\uD83D\uDC77\uD83C\uDFFE", + [":construction_worker_tone5:"] = "\uD83D\uDC77\uD83C\uDFFF", + [":control_knobs:"] = "\uD83C\uDF9B️", + [":convenience_store:"] = "\uD83C\uDFEA", + [":cookie:"] = "\uD83C\uDF6A", + [":cooking:"] = "\uD83C\uDF73", + [":cool:"] = "\uD83C\uDD92", + [":cop:"] = "\uD83D\uDC6E", + [":cop::skin-tone-1:"] = "\uD83D\uDC6E\uD83C\uDFFB", + [":cop::skin-tone-2:"] = "\uD83D\uDC6E\uD83C\uDFFC", + [":cop::skin-tone-3:"] = "\uD83D\uDC6E\uD83C\uDFFD", + [":cop::skin-tone-4:"] = "\uD83D\uDC6E\uD83C\uDFFE", + [":cop::skin-tone-5:"] = "\uD83D\uDC6E\uD83C\uDFFF", + [":cop_tone1:"] = "\uD83D\uDC6E\uD83C\uDFFB", + [":cop_tone2:"] = "\uD83D\uDC6E\uD83C\uDFFC", + [":cop_tone3:"] = "\uD83D\uDC6E\uD83C\uDFFD", + [":cop_tone4:"] = "\uD83D\uDC6E\uD83C\uDFFE", + [":cop_tone5:"] = "\uD83D\uDC6E\uD83C\uDFFF", + [":copyright:"] = "©️", + [":corn:"] = "\uD83C\uDF3D", + [":couch:"] = "\uD83D\uDECB️", + [":couch_and_lamp:"] = "\uD83D\uDECB️", + [":couple:"] = "\uD83D\uDC6B", + [":couple_mm:"] = "\uD83D\uDC68\u200D❤️\u200D\uD83D\uDC68", + [":couple_with_heart:"] = "\uD83D\uDC91", + [":couple_with_heart_mm:"] = "\uD83D\uDC68\u200D❤️\u200D\uD83D\uDC68", + [":couple_with_heart_woman_man:"] = "\uD83D\uDC69\u200D❤️\u200D\uD83D\uDC68", + [":couple_with_heart_ww:"] = "\uD83D\uDC69\u200D❤️\u200D\uD83D\uDC69", + [":couple_ww:"] = "\uD83D\uDC69\u200D❤️\u200D\uD83D\uDC69", + [":couplekiss:"] = "\uD83D\uDC8F", + [":couplekiss_mm:"] = "\uD83D\uDC68\u200D❤️\u200D\uD83D\uDC8B\u200D\uD83D\uDC68", + [":couplekiss_ww:"] = "\uD83D\uDC69\u200D❤️\u200D\uD83D\uDC8B\u200D\uD83D\uDC69", + [":cow2:"] = "\uD83D\uDC04", + [":cow:"] = "\uD83D\uDC2E", + [":cowboy:"] = "\uD83E\uDD20", + [":crab:"] = "\uD83E\uDD80", + [":crayon:"] = "\uD83D\uDD8D️", + [":credit_card:"] = "\uD83D\uDCB3", + [":crescent_moon:"] = "\uD83C\uDF19", + [":cricket:"] = "\uD83E\uDD97", + [":cricket_bat_ball:"] = "\uD83C\uDFCF", + [":cricket_game:"] = "\uD83C\uDFCF", + [":crocodile:"] = "\uD83D\uDC0A", + [":croissant:"] = "\uD83E\uDD50", + [":cross:"] = "✝️", + [":crossed_flags:"] = "\uD83C\uDF8C", + [":crossed_swords:"] = "⚔️", + [":crown:"] = "\uD83D\uDC51", + [":cruise_ship:"] = "\uD83D\uDEF3️", + [":cry:"] = "\uD83D\uDE22", + [":crying_cat_face:"] = "\uD83D\uDE3F", + [":crystal_ball:"] = "\uD83D\uDD2E", + [":cucumber:"] = "\uD83E\uDD52", + [":cup_with_straw:"] = "\uD83E\uDD64", + [":cupcake:"] = "\uD83E\uDDC1", + [":cupid:"] = "\uD83D\uDC98", + [":curling_stone:"] = "\uD83E\uDD4C", + [":curly_loop:"] = "➰", + [":currency_exchange:"] = "\uD83D\uDCB1", + [":curry:"] = "\uD83C\uDF5B", + [":custard:"] = "\uD83C\uDF6E", + [":customs:"] = "\uD83D\uDEC3", + [":cut_of_meat:"] = "\uD83E\uDD69", + [":cyclone:"] = "\uD83C\uDF00", + [":dagger:"] = "\uD83D\uDDE1️", + [":dagger_knife:"] = "\uD83D\uDDE1️", + [":dancer:"] = "\uD83D\uDC83", + [":dancer::skin-tone-1:"] = "\uD83D\uDC83\uD83C\uDFFB", + [":dancer::skin-tone-2:"] = "\uD83D\uDC83\uD83C\uDFFC", + [":dancer::skin-tone-3:"] = "\uD83D\uDC83\uD83C\uDFFD", + [":dancer::skin-tone-4:"] = "\uD83D\uDC83\uD83C\uDFFE", + [":dancer::skin-tone-5:"] = "\uD83D\uDC83\uD83C\uDFFF", + [":dancer_tone1:"] = "\uD83D\uDC83\uD83C\uDFFB", + [":dancer_tone2:"] = "\uD83D\uDC83\uD83C\uDFFC", + [":dancer_tone3:"] = "\uD83D\uDC83\uD83C\uDFFD", + [":dancer_tone4:"] = "\uD83D\uDC83\uD83C\uDFFE", + [":dancer_tone5:"] = "\uD83D\uDC83\uD83C\uDFFF", + [":dancers:"] = "\uD83D\uDC6F", + [":dango:"] = "\uD83C\uDF61", + [":dark_sunglasses:"] = "\uD83D\uDD76️", + [":dart:"] = "\uD83C\uDFAF", + [":dash:"] = "\uD83D\uDCA8", + [":date:"] = "\uD83D\uDCC5", + [":deaf_man:"] = "\uD83E\uDDCF\u200D♂️", + [":deaf_man::skin-tone-1:"] = "\uD83E\uDDCF\uD83C\uDFFB\u200D♂️", + [":deaf_man::skin-tone-2:"] = "\uD83E\uDDCF\uD83C\uDFFC\u200D♂️", + [":deaf_man::skin-tone-3:"] = "\uD83E\uDDCF\uD83C\uDFFD\u200D♂️", + [":deaf_man::skin-tone-4:"] = "\uD83E\uDDCF\uD83C\uDFFE\u200D♂️", + [":deaf_man::skin-tone-5:"] = "\uD83E\uDDCF\uD83C\uDFFF\u200D♂️", + [":deaf_man_dark_skin_tone:"] = "\uD83E\uDDCF\uD83C\uDFFF\u200D♂️", + [":deaf_man_light_skin_tone:"] = "\uD83E\uDDCF\uD83C\uDFFB\u200D♂️", + [":deaf_man_medium_dark_skin_tone:"] = "\uD83E\uDDCF\uD83C\uDFFE\u200D♂️", + [":deaf_man_medium_light_skin_tone:"] = "\uD83E\uDDCF\uD83C\uDFFC\u200D♂️", + [":deaf_man_medium_skin_tone:"] = "\uD83E\uDDCF\uD83C\uDFFD\u200D♂️", + [":deaf_man_tone1:"] = "\uD83E\uDDCF\uD83C\uDFFB\u200D♂️", + [":deaf_man_tone2:"] = "\uD83E\uDDCF\uD83C\uDFFC\u200D♂️", + [":deaf_man_tone3:"] = "\uD83E\uDDCF\uD83C\uDFFD\u200D♂️", + [":deaf_man_tone4:"] = "\uD83E\uDDCF\uD83C\uDFFE\u200D♂️", + [":deaf_man_tone5:"] = "\uD83E\uDDCF\uD83C\uDFFF\u200D♂️", + [":deaf_person:"] = "\uD83E\uDDCF", + [":deaf_person::skin-tone-1:"] = "\uD83E\uDDCF\uD83C\uDFFB", + [":deaf_person::skin-tone-2:"] = "\uD83E\uDDCF\uD83C\uDFFC", + [":deaf_person::skin-tone-3:"] = "\uD83E\uDDCF\uD83C\uDFFD", + [":deaf_person::skin-tone-4:"] = "\uD83E\uDDCF\uD83C\uDFFE", + [":deaf_person::skin-tone-5:"] = "\uD83E\uDDCF\uD83C\uDFFF", + [":deaf_person_dark_skin_tone:"] = "\uD83E\uDDCF\uD83C\uDFFF", + [":deaf_person_light_skin_tone:"] = "\uD83E\uDDCF\uD83C\uDFFB", + [":deaf_person_medium_dark_skin_tone:"] = "\uD83E\uDDCF\uD83C\uDFFE", + [":deaf_person_medium_light_skin_tone:"] = "\uD83E\uDDCF\uD83C\uDFFC", + [":deaf_person_medium_skin_tone:"] = "\uD83E\uDDCF\uD83C\uDFFD", + [":deaf_person_tone1:"] = "\uD83E\uDDCF\uD83C\uDFFB", + [":deaf_person_tone2:"] = "\uD83E\uDDCF\uD83C\uDFFC", + [":deaf_person_tone3:"] = "\uD83E\uDDCF\uD83C\uDFFD", + [":deaf_person_tone4:"] = "\uD83E\uDDCF\uD83C\uDFFE", + [":deaf_person_tone5:"] = "\uD83E\uDDCF\uD83C\uDFFF", + [":deaf_woman:"] = "\uD83E\uDDCF\u200D♀️", + [":deaf_woman::skin-tone-1:"] = "\uD83E\uDDCF\uD83C\uDFFB\u200D♀️", + [":deaf_woman::skin-tone-2:"] = "\uD83E\uDDCF\uD83C\uDFFC\u200D♀️", + [":deaf_woman::skin-tone-3:"] = "\uD83E\uDDCF\uD83C\uDFFD\u200D♀️", + [":deaf_woman::skin-tone-4:"] = "\uD83E\uDDCF\uD83C\uDFFE\u200D♀️", + [":deaf_woman::skin-tone-5:"] = "\uD83E\uDDCF\uD83C\uDFFF\u200D♀️", + [":deaf_woman_dark_skin_tone:"] = "\uD83E\uDDCF\uD83C\uDFFF\u200D♀️", + [":deaf_woman_light_skin_tone:"] = "\uD83E\uDDCF\uD83C\uDFFB\u200D♀️", + [":deaf_woman_medium_dark_skin_tone:"] = "\uD83E\uDDCF\uD83C\uDFFE\u200D♀️", + [":deaf_woman_medium_light_skin_tone:"] = "\uD83E\uDDCF\uD83C\uDFFC\u200D♀️", + [":deaf_woman_medium_skin_tone:"] = "\uD83E\uDDCF\uD83C\uDFFD\u200D♀️", + [":deaf_woman_tone1:"] = "\uD83E\uDDCF\uD83C\uDFFB\u200D♀️", + [":deaf_woman_tone2:"] = "\uD83E\uDDCF\uD83C\uDFFC\u200D♀️", + [":deaf_woman_tone3:"] = "\uD83E\uDDCF\uD83C\uDFFD\u200D♀️", + [":deaf_woman_tone4:"] = "\uD83E\uDDCF\uD83C\uDFFE\u200D♀️", + [":deaf_woman_tone5:"] = "\uD83E\uDDCF\uD83C\uDFFF\u200D♀️", + [":deciduous_tree:"] = "\uD83C\uDF33", + [":deer:"] = "\uD83E\uDD8C", + [":department_store:"] = "\uD83C\uDFEC", + [":derelict_house_building:"] = "\uD83C\uDFDA️", + [":desert:"] = "\uD83C\uDFDC️", + [":desert_island:"] = "\uD83C\uDFDD️", + [":desktop:"] = "\uD83D\uDDA5️", + [":desktop_computer:"] = "\uD83D\uDDA5️", + [":detective:"] = "\uD83D\uDD75️", + [":detective::skin-tone-1:"] = "\uD83D\uDD75\uD83C\uDFFB", + [":detective::skin-tone-2:"] = "\uD83D\uDD75\uD83C\uDFFC", + [":detective::skin-tone-3:"] = "\uD83D\uDD75\uD83C\uDFFD", + [":detective::skin-tone-4:"] = "\uD83D\uDD75\uD83C\uDFFE", + [":detective::skin-tone-5:"] = "\uD83D\uDD75\uD83C\uDFFF", + [":detective_tone1:"] = "\uD83D\uDD75\uD83C\uDFFB", + [":detective_tone2:"] = "\uD83D\uDD75\uD83C\uDFFC", + [":detective_tone3:"] = "\uD83D\uDD75\uD83C\uDFFD", + [":detective_tone4:"] = "\uD83D\uDD75\uD83C\uDFFE", + [":detective_tone5:"] = "\uD83D\uDD75\uD83C\uDFFF", + [":diamond_shape_with_a_dot_inside:"] = "\uD83D\uDCA0", + [":diamonds:"] = "♦️", + [":disappointed:"] = "\uD83D\uDE1E", + [":disappointed_relieved:"] = "\uD83D\uDE25", + [":dividers:"] = "\uD83D\uDDC2️", + [":diving_mask:"] = "\uD83E\uDD3F", + [":diya_lamp:"] = "\uD83E\uDE94", + [":dizzy:"] = "\uD83D\uDCAB", + [":dizzy_face:"] = "\uD83D\uDE35", + [":dna:"] = "\uD83E\uDDEC", + [":do_not_litter:"] = "\uD83D\uDEAF", + [":dog2:"] = "\uD83D\uDC15", + [":dog:"] = "\uD83D\uDC36", + [":dollar:"] = "\uD83D\uDCB5", + [":dolls:"] = "\uD83C\uDF8E", + [":dolphin:"] = "\uD83D\uDC2C", + [":door:"] = "\uD83D\uDEAA", + [":double_vertical_bar:"] = "⏸️", + [":doughnut:"] = "\uD83C\uDF69", + [":dove:"] = "\uD83D\uDD4A️", + [":dove_of_peace:"] = "\uD83D\uDD4A️", + [":dragon:"] = "\uD83D\uDC09", + [":dragon_face:"] = "\uD83D\uDC32", + [":dress:"] = "\uD83D\uDC57", + [":dromedary_camel:"] = "\uD83D\uDC2A", + [":drool:"] = "\uD83E\uDD24", + [":drooling_face:"] = "\uD83E\uDD24", + [":drop_of_blood:"] = "\uD83E\uDE78", + [":droplet:"] = "\uD83D\uDCA7", + [":drum:"] = "\uD83E\uDD41", + [":drum_with_drumsticks:"] = "\uD83E\uDD41", + [":duck:"] = "\uD83E\uDD86", + [":dumpling:"] = "\uD83E\uDD5F", + [":dvd:"] = "\uD83D\uDCC0", + [":e_mail:"] = "\uD83D\uDCE7", + [":eagle:"] = "\uD83E\uDD85", + [":ear:"] = "\uD83D\uDC42", + [":ear::skin-tone-1:"] = "\uD83D\uDC42\uD83C\uDFFB", + [":ear::skin-tone-2:"] = "\uD83D\uDC42\uD83C\uDFFC", + [":ear::skin-tone-3:"] = "\uD83D\uDC42\uD83C\uDFFD", + [":ear::skin-tone-4:"] = "\uD83D\uDC42\uD83C\uDFFE", + [":ear::skin-tone-5:"] = "\uD83D\uDC42\uD83C\uDFFF", + [":ear_of_rice:"] = "\uD83C\uDF3E", + [":ear_tone1:"] = "\uD83D\uDC42\uD83C\uDFFB", + [":ear_tone2:"] = "\uD83D\uDC42\uD83C\uDFFC", + [":ear_tone3:"] = "\uD83D\uDC42\uD83C\uDFFD", + [":ear_tone4:"] = "\uD83D\uDC42\uD83C\uDFFE", + [":ear_tone5:"] = "\uD83D\uDC42\uD83C\uDFFF", + [":ear_with_hearing_aid:"] = "\uD83E\uDDBB", + [":ear_with_hearing_aid::skin-tone-1:"] = "\uD83E\uDDBB\uD83C\uDFFB", + [":ear_with_hearing_aid::skin-tone-2:"] = "\uD83E\uDDBB\uD83C\uDFFC", + [":ear_with_hearing_aid::skin-tone-3:"] = "\uD83E\uDDBB\uD83C\uDFFD", + [":ear_with_hearing_aid::skin-tone-4:"] = "\uD83E\uDDBB\uD83C\uDFFE", + [":ear_with_hearing_aid::skin-tone-5:"] = "\uD83E\uDDBB\uD83C\uDFFF", + [":ear_with_hearing_aid_dark_skin_tone:"] = "\uD83E\uDDBB\uD83C\uDFFF", + [":ear_with_hearing_aid_light_skin_tone:"] = "\uD83E\uDDBB\uD83C\uDFFB", + [":ear_with_hearing_aid_medium_dark_skin_tone:"] = "\uD83E\uDDBB\uD83C\uDFFE", + [":ear_with_hearing_aid_medium_light_skin_tone:"] = "\uD83E\uDDBB\uD83C\uDFFC", + [":ear_with_hearing_aid_medium_skin_tone:"] = "\uD83E\uDDBB\uD83C\uDFFD", + [":ear_with_hearing_aid_tone1:"] = "\uD83E\uDDBB\uD83C\uDFFB", + [":ear_with_hearing_aid_tone2:"] = "\uD83E\uDDBB\uD83C\uDFFC", + [":ear_with_hearing_aid_tone3:"] = "\uD83E\uDDBB\uD83C\uDFFD", + [":ear_with_hearing_aid_tone4:"] = "\uD83E\uDDBB\uD83C\uDFFE", + [":ear_with_hearing_aid_tone5:"] = "\uD83E\uDDBB\uD83C\uDFFF", + [":earth_africa:"] = "\uD83C\uDF0D", + [":earth_americas:"] = "\uD83C\uDF0E", + [":earth_asia:"] = "\uD83C\uDF0F", + [":egg:"] = "\uD83E\uDD5A", + [":eggplant:"] = "\uD83C\uDF46", + [":eight:"] = "8️⃣", + [":eight_pointed_black_star:"] = "✴️", + [":eight_spoked_asterisk:"] = "✳️", + [":eject:"] = "⏏️", + [":eject_symbol:"] = "⏏️", + [":electric_plug:"] = "\uD83D\uDD0C", + [":elephant:"] = "\uD83D\uDC18", + [":elf:"] = "\uD83E\uDDDD", + [":elf::skin-tone-1:"] = "\uD83E\uDDDD\uD83C\uDFFB", + [":elf::skin-tone-2:"] = "\uD83E\uDDDD\uD83C\uDFFC", + [":elf::skin-tone-3:"] = "\uD83E\uDDDD\uD83C\uDFFD", + [":elf::skin-tone-4:"] = "\uD83E\uDDDD\uD83C\uDFFE", + [":elf::skin-tone-5:"] = "\uD83E\uDDDD\uD83C\uDFFF", + [":elf_dark_skin_tone:"] = "\uD83E\uDDDD\uD83C\uDFFF", + [":elf_light_skin_tone:"] = "\uD83E\uDDDD\uD83C\uDFFB", + [":elf_medium_dark_skin_tone:"] = "\uD83E\uDDDD\uD83C\uDFFE", + [":elf_medium_light_skin_tone:"] = "\uD83E\uDDDD\uD83C\uDFFC", + [":elf_medium_skin_tone:"] = "\uD83E\uDDDD\uD83C\uDFFD", + [":elf_tone1:"] = "\uD83E\uDDDD\uD83C\uDFFB", + [":elf_tone2:"] = "\uD83E\uDDDD\uD83C\uDFFC", + [":elf_tone3:"] = "\uD83E\uDDDD\uD83C\uDFFD", + [":elf_tone4:"] = "\uD83E\uDDDD\uD83C\uDFFE", + [":elf_tone5:"] = "\uD83E\uDDDD\uD83C\uDFFF", + [":email:"] = "\uD83D\uDCE7", + [":end:"] = "\uD83D\uDD1A", + [":england:"] = "\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67\uDB40\uDC7F", + [":envelope:"] = "✉️", + [":envelope_with_arrow:"] = "\uD83D\uDCE9", + [":euro:"] = "\uD83D\uDCB6", + [":european_castle:"] = "\uD83C\uDFF0", + [":european_post_office:"] = "\uD83C\uDFE4", + [":evergreen_tree:"] = "\uD83C\uDF32", + [":exclamation:"] = "❗", + [":expecting_woman:"] = "\uD83E\uDD30", + [":expecting_woman::skin-tone-1:"] = "\uD83E\uDD30\uD83C\uDFFB", + [":expecting_woman::skin-tone-2:"] = "\uD83E\uDD30\uD83C\uDFFC", + [":expecting_woman::skin-tone-3:"] = "\uD83E\uDD30\uD83C\uDFFD", + [":expecting_woman::skin-tone-4:"] = "\uD83E\uDD30\uD83C\uDFFE", + [":expecting_woman::skin-tone-5:"] = "\uD83E\uDD30\uD83C\uDFFF", + [":expecting_woman_tone1:"] = "\uD83E\uDD30\uD83C\uDFFB", + [":expecting_woman_tone2:"] = "\uD83E\uDD30\uD83C\uDFFC", + [":expecting_woman_tone3:"] = "\uD83E\uDD30\uD83C\uDFFD", + [":expecting_woman_tone4:"] = "\uD83E\uDD30\uD83C\uDFFE", + [":expecting_woman_tone5:"] = "\uD83E\uDD30\uD83C\uDFFF", + [":exploding_head:"] = "\uD83E\uDD2F", + [":expressionless:"] = "\uD83D\uDE11", + [":eye:"] = "\uD83D\uDC41️", + [":eye_in_speech_bubble:"] = "\uD83D\uDC41\u200D\uD83D\uDDE8", + [":eyeglasses:"] = "\uD83D\uDC53", + [":eyes:"] = "\uD83D\uDC40", + [":face_palm:"] = "\uD83E\uDD26", + [":face_palm::skin-tone-1:"] = "\uD83E\uDD26\uD83C\uDFFB", + [":face_palm::skin-tone-2:"] = "\uD83E\uDD26\uD83C\uDFFC", + [":face_palm::skin-tone-3:"] = "\uD83E\uDD26\uD83C\uDFFD", + [":face_palm::skin-tone-4:"] = "\uD83E\uDD26\uD83C\uDFFE", + [":face_palm::skin-tone-5:"] = "\uD83E\uDD26\uD83C\uDFFF", + [":face_palm_tone1:"] = "\uD83E\uDD26\uD83C\uDFFB", + [":face_palm_tone2:"] = "\uD83E\uDD26\uD83C\uDFFC", + [":face_palm_tone3:"] = "\uD83E\uDD26\uD83C\uDFFD", + [":face_palm_tone4:"] = "\uD83E\uDD26\uD83C\uDFFE", + [":face_palm_tone5:"] = "\uD83E\uDD26\uD83C\uDFFF", + [":face_vomiting:"] = "\uD83E\uDD2E", + [":face_with_cowboy_hat:"] = "\uD83E\uDD20", + [":face_with_hand_over_mouth:"] = "\uD83E\uDD2D", + [":face_with_head_bandage:"] = "\uD83E\uDD15", + [":face_with_monocle:"] = "\uD83E\uDDD0", + [":face_with_raised_eyebrow:"] = "\uD83E\uDD28", + [":face_with_rolling_eyes:"] = "\uD83D\uDE44", + [":face_with_symbols_over_mouth:"] = "\uD83E\uDD2C", + [":face_with_thermometer:"] = "\uD83E\uDD12", + [":facepalm:"] = "\uD83E\uDD26", + [":facepalm::skin-tone-1:"] = "\uD83E\uDD26\uD83C\uDFFB", + [":facepalm::skin-tone-2:"] = "\uD83E\uDD26\uD83C\uDFFC", + [":facepalm::skin-tone-3:"] = "\uD83E\uDD26\uD83C\uDFFD", + [":facepalm::skin-tone-4:"] = "\uD83E\uDD26\uD83C\uDFFE", + [":facepalm::skin-tone-5:"] = "\uD83E\uDD26\uD83C\uDFFF", + [":facepalm_tone1:"] = "\uD83E\uDD26\uD83C\uDFFB", + [":facepalm_tone2:"] = "\uD83E\uDD26\uD83C\uDFFC", + [":facepalm_tone3:"] = "\uD83E\uDD26\uD83C\uDFFD", + [":facepalm_tone4:"] = "\uD83E\uDD26\uD83C\uDFFE", + [":facepalm_tone5:"] = "\uD83E\uDD26\uD83C\uDFFF", + [":factory:"] = "\uD83C\uDFED", + [":fairy:"] = "\uD83E\uDDDA", + [":fairy::skin-tone-1:"] = "\uD83E\uDDDA\uD83C\uDFFB", + [":fairy::skin-tone-2:"] = "\uD83E\uDDDA\uD83C\uDFFC", + [":fairy::skin-tone-3:"] = "\uD83E\uDDDA\uD83C\uDFFD", + [":fairy::skin-tone-4:"] = "\uD83E\uDDDA\uD83C\uDFFE", + [":fairy::skin-tone-5:"] = "\uD83E\uDDDA\uD83C\uDFFF", + [":fairy_dark_skin_tone:"] = "\uD83E\uDDDA\uD83C\uDFFF", + [":fairy_light_skin_tone:"] = "\uD83E\uDDDA\uD83C\uDFFB", + [":fairy_medium_dark_skin_tone:"] = "\uD83E\uDDDA\uD83C\uDFFE", + [":fairy_medium_light_skin_tone:"] = "\uD83E\uDDDA\uD83C\uDFFC", + [":fairy_medium_skin_tone:"] = "\uD83E\uDDDA\uD83C\uDFFD", + [":fairy_tone1:"] = "\uD83E\uDDDA\uD83C\uDFFB", + [":fairy_tone2:"] = "\uD83E\uDDDA\uD83C\uDFFC", + [":fairy_tone3:"] = "\uD83E\uDDDA\uD83C\uDFFD", + [":fairy_tone4:"] = "\uD83E\uDDDA\uD83C\uDFFE", + [":fairy_tone5:"] = "\uD83E\uDDDA\uD83C\uDFFF", + [":falafel:"] = "\uD83E\uDDC6", + [":fallen_leaf:"] = "\uD83C\uDF42", + [":family:"] = "\uD83D\uDC6A", + [":family_man_boy:"] = "\uD83D\uDC68\u200D\uD83D\uDC66", + [":family_man_boy_boy:"] = "\uD83D\uDC68\u200D\uD83D\uDC66\u200D\uD83D\uDC66", + [":family_man_girl:"] = "\uD83D\uDC68\u200D\uD83D\uDC67", + [":family_man_girl_boy:"] = "\uD83D\uDC68\u200D\uD83D\uDC67\u200D\uD83D\uDC66", + [":family_man_girl_girl:"] = "\uD83D\uDC68\u200D\uD83D\uDC67\u200D\uD83D\uDC67", + [":family_man_woman_boy:"] = "\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC66", + [":family_mmb:"] = "\uD83D\uDC68\u200D\uD83D\uDC68\u200D\uD83D\uDC66", + [":family_mmbb:"] = "\uD83D\uDC68\u200D\uD83D\uDC68\u200D\uD83D\uDC66\u200D\uD83D\uDC66", + [":family_mmg:"] = "\uD83D\uDC68\u200D\uD83D\uDC68\u200D\uD83D\uDC67", + [":family_mmgb:"] = "\uD83D\uDC68\u200D\uD83D\uDC68\u200D\uD83D\uDC67\u200D\uD83D\uDC66", + [":family_mmgg:"] = "\uD83D\uDC68\u200D\uD83D\uDC68\u200D\uD83D\uDC67\u200D\uD83D\uDC67", + [":family_mwbb:"] = "\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66", + [":family_mwg:"] = "\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67", + [":family_mwgb:"] = "\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC66", + [":family_mwgg:"] = "\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC67", + [":family_woman_boy:"] = "\uD83D\uDC69\u200D\uD83D\uDC66", + [":family_woman_boy_boy:"] = "\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66", + [":family_woman_girl:"] = "\uD83D\uDC69\u200D\uD83D\uDC67", + [":family_woman_girl_boy:"] = "\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC66", + [":family_woman_girl_girl:"] = "\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC67", + [":family_wwb:"] = "\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC66", + [":family_wwbb:"] = "\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66", + [":family_wwg:"] = "\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC67", + [":family_wwgb:"] = "\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC66", + [":family_wwgg:"] = "\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC67", + [":fast_forward:"] = "⏩", + [":fax:"] = "\uD83D\uDCE0", + [":fearful:"] = "\uD83D\uDE28", + [":feet:"] = "\uD83D\uDC3E", + [":female_sign:"] = "♀️", + [":fencer:"] = "\uD83E\uDD3A", + [":fencing:"] = "\uD83E\uDD3A", + [":ferris_wheel:"] = "\uD83C\uDFA1", + [":ferry:"] = "⛴️", + [":field_hockey:"] = "\uD83C\uDFD1", + [":file_cabinet:"] = "\uD83D\uDDC4️", + [":file_folder:"] = "\uD83D\uDCC1", + [":film_frames:"] = "\uD83C\uDF9E️", + [":film_projector:"] = "\uD83D\uDCFD️", + [":fingers_crossed:"] = "\uD83E\uDD1E", + [":fingers_crossed::skin-tone-1:"] = "\uD83E\uDD1E\uD83C\uDFFB", + [":fingers_crossed::skin-tone-2:"] = "\uD83E\uDD1E\uD83C\uDFFC", + [":fingers_crossed::skin-tone-3:"] = "\uD83E\uDD1E\uD83C\uDFFD", + [":fingers_crossed::skin-tone-4:"] = "\uD83E\uDD1E\uD83C\uDFFE", + [":fingers_crossed::skin-tone-5:"] = "\uD83E\uDD1E\uD83C\uDFFF", + [":fingers_crossed_tone1:"] = "\uD83E\uDD1E\uD83C\uDFFB", + [":fingers_crossed_tone2:"] = "\uD83E\uDD1E\uD83C\uDFFC", + [":fingers_crossed_tone3:"] = "\uD83E\uDD1E\uD83C\uDFFD", + [":fingers_crossed_tone4:"] = "\uD83E\uDD1E\uD83C\uDFFE", + [":fingers_crossed_tone5:"] = "\uD83E\uDD1E\uD83C\uDFFF", + [":fire:"] = "\uD83D\uDD25", + [":fire_engine:"] = "\uD83D\uDE92", + [":fire_extinguisher:"] = "\uD83E\uDDEF", + [":firecracker:"] = "\uD83E\uDDE8", + [":fireworks:"] = "\uD83C\uDF86", + [":first_place:"] = "\uD83E\uDD47", + [":first_place_medal:"] = "\uD83E\uDD47", + [":first_quarter_moon:"] = "\uD83C\uDF13", + [":first_quarter_moon_with_face:"] = "\uD83C\uDF1B", + [":fish:"] = "\uD83D\uDC1F", + [":fish_cake:"] = "\uD83C\uDF65", + [":fishing_pole_and_fish:"] = "\uD83C\uDFA3", + [":fist:"] = "✊", + [":fist::skin-tone-1:"] = "✊\uD83C\uDFFB", + [":fist::skin-tone-2:"] = "✊\uD83C\uDFFC", + [":fist::skin-tone-3:"] = "✊\uD83C\uDFFD", + [":fist::skin-tone-4:"] = "✊\uD83C\uDFFE", + [":fist::skin-tone-5:"] = "✊\uD83C\uDFFF", + [":fist_tone1:"] = "✊\uD83C\uDFFB", + [":fist_tone2:"] = "✊\uD83C\uDFFC", + [":fist_tone3:"] = "✊\uD83C\uDFFD", + [":fist_tone4:"] = "✊\uD83C\uDFFE", + [":fist_tone5:"] = "✊\uD83C\uDFFF", + [":five:"] = "5️⃣", + [":flag_ac:"] = "\uD83C\uDDE6\uD83C\uDDE8", + [":flag_ad:"] = "\uD83C\uDDE6\uD83C\uDDE9", + [":flag_ae:"] = "\uD83C\uDDE6\uD83C\uDDEA", + [":flag_af:"] = "\uD83C\uDDE6\uD83C\uDDEB", + [":flag_ag:"] = "\uD83C\uDDE6\uD83C\uDDEC", + [":flag_ai:"] = "\uD83C\uDDE6\uD83C\uDDEE", + [":flag_al:"] = "\uD83C\uDDE6\uD83C\uDDF1", + [":flag_am:"] = "\uD83C\uDDE6\uD83C\uDDF2", + [":flag_ao:"] = "\uD83C\uDDE6\uD83C\uDDF4", + [":flag_aq:"] = "\uD83C\uDDE6\uD83C\uDDF6", + [":flag_ar:"] = "\uD83C\uDDE6\uD83C\uDDF7", + [":flag_as:"] = "\uD83C\uDDE6\uD83C\uDDF8", + [":flag_at:"] = "\uD83C\uDDE6\uD83C\uDDF9", + [":flag_au:"] = "\uD83C\uDDE6\uD83C\uDDFA", + [":flag_aw:"] = "\uD83C\uDDE6\uD83C\uDDFC", + [":flag_ax:"] = "\uD83C\uDDE6\uD83C\uDDFD", + [":flag_az:"] = "\uD83C\uDDE6\uD83C\uDDFF", + [":flag_ba:"] = "\uD83C\uDDE7\uD83C\uDDE6", + [":flag_bb:"] = "\uD83C\uDDE7\uD83C\uDDE7", + [":flag_bd:"] = "\uD83C\uDDE7\uD83C\uDDE9", + [":flag_be:"] = "\uD83C\uDDE7\uD83C\uDDEA", + [":flag_bf:"] = "\uD83C\uDDE7\uD83C\uDDEB", + [":flag_bg:"] = "\uD83C\uDDE7\uD83C\uDDEC", + [":flag_bh:"] = "\uD83C\uDDE7\uD83C\uDDED", + [":flag_bi:"] = "\uD83C\uDDE7\uD83C\uDDEE", + [":flag_bj:"] = "\uD83C\uDDE7\uD83C\uDDEF", + [":flag_bl:"] = "\uD83C\uDDE7\uD83C\uDDF1", + [":flag_black:"] = "\uD83C\uDFF4", + [":flag_bm:"] = "\uD83C\uDDE7\uD83C\uDDF2", + [":flag_bn:"] = "\uD83C\uDDE7\uD83C\uDDF3", + [":flag_bo:"] = "\uD83C\uDDE7\uD83C\uDDF4", + [":flag_bq:"] = "\uD83C\uDDE7\uD83C\uDDF6", + [":flag_br:"] = "\uD83C\uDDE7\uD83C\uDDF7", + [":flag_bs:"] = "\uD83C\uDDE7\uD83C\uDDF8", + [":flag_bt:"] = "\uD83C\uDDE7\uD83C\uDDF9", + [":flag_bv:"] = "\uD83C\uDDE7\uD83C\uDDFB", + [":flag_bw:"] = "\uD83C\uDDE7\uD83C\uDDFC", + [":flag_by:"] = "\uD83C\uDDE7\uD83C\uDDFE", + [":flag_bz:"] = "\uD83C\uDDE7\uD83C\uDDFF", + [":flag_ca:"] = "\uD83C\uDDE8\uD83C\uDDE6", + [":flag_cc:"] = "\uD83C\uDDE8\uD83C\uDDE8", + [":flag_cd:"] = "\uD83C\uDDE8\uD83C\uDDE9", + [":flag_cf:"] = "\uD83C\uDDE8\uD83C\uDDEB", + [":flag_cg:"] = "\uD83C\uDDE8\uD83C\uDDEC", + [":flag_ch:"] = "\uD83C\uDDE8\uD83C\uDDED", + [":flag_ci:"] = "\uD83C\uDDE8\uD83C\uDDEE", + [":flag_ck:"] = "\uD83C\uDDE8\uD83C\uDDF0", + [":flag_cl:"] = "\uD83C\uDDE8\uD83C\uDDF1", + [":flag_cm:"] = "\uD83C\uDDE8\uD83C\uDDF2", + [":flag_cn:"] = "\uD83C\uDDE8\uD83C\uDDF3", + [":flag_co:"] = "\uD83C\uDDE8\uD83C\uDDF4", + [":flag_cp:"] = "\uD83C\uDDE8\uD83C\uDDF5", + [":flag_cr:"] = "\uD83C\uDDE8\uD83C\uDDF7", + [":flag_cu:"] = "\uD83C\uDDE8\uD83C\uDDFA", + [":flag_cv:"] = "\uD83C\uDDE8\uD83C\uDDFB", + [":flag_cw:"] = "\uD83C\uDDE8\uD83C\uDDFC", + [":flag_cx:"] = "\uD83C\uDDE8\uD83C\uDDFD", + [":flag_cy:"] = "\uD83C\uDDE8\uD83C\uDDFE", + [":flag_cz:"] = "\uD83C\uDDE8\uD83C\uDDFF", + [":flag_de:"] = "\uD83C\uDDE9\uD83C\uDDEA", + [":flag_dg:"] = "\uD83C\uDDE9\uD83C\uDDEC", + [":flag_dj:"] = "\uD83C\uDDE9\uD83C\uDDEF", + [":flag_dk:"] = "\uD83C\uDDE9\uD83C\uDDF0", + [":flag_dm:"] = "\uD83C\uDDE9\uD83C\uDDF2", + [":flag_do:"] = "\uD83C\uDDE9\uD83C\uDDF4", + [":flag_dz:"] = "\uD83C\uDDE9\uD83C\uDDFF", + [":flag_ea:"] = "\uD83C\uDDEA\uD83C\uDDE6", + [":flag_ec:"] = "\uD83C\uDDEA\uD83C\uDDE8", + [":flag_ee:"] = "\uD83C\uDDEA\uD83C\uDDEA", + [":flag_eg:"] = "\uD83C\uDDEA\uD83C\uDDEC", + [":flag_eh:"] = "\uD83C\uDDEA\uD83C\uDDED", + [":flag_er:"] = "\uD83C\uDDEA\uD83C\uDDF7", + [":flag_es:"] = "\uD83C\uDDEA\uD83C\uDDF8", + [":flag_et:"] = "\uD83C\uDDEA\uD83C\uDDF9", + [":flag_eu:"] = "\uD83C\uDDEA\uD83C\uDDFA", + [":flag_fi:"] = "\uD83C\uDDEB\uD83C\uDDEE", + [":flag_fj:"] = "\uD83C\uDDEB\uD83C\uDDEF", + [":flag_fk:"] = "\uD83C\uDDEB\uD83C\uDDF0", + [":flag_fm:"] = "\uD83C\uDDEB\uD83C\uDDF2", + [":flag_fo:"] = "\uD83C\uDDEB\uD83C\uDDF4", + [":flag_fr:"] = "\uD83C\uDDEB\uD83C\uDDF7", + [":flag_ga:"] = "\uD83C\uDDEC\uD83C\uDDE6", + [":flag_gb:"] = "\uD83C\uDDEC\uD83C\uDDE7", + [":flag_gd:"] = "\uD83C\uDDEC\uD83C\uDDE9", + [":flag_ge:"] = "\uD83C\uDDEC\uD83C\uDDEA", + [":flag_gf:"] = "\uD83C\uDDEC\uD83C\uDDEB", + [":flag_gg:"] = "\uD83C\uDDEC\uD83C\uDDEC", + [":flag_gh:"] = "\uD83C\uDDEC\uD83C\uDDED", + [":flag_gi:"] = "\uD83C\uDDEC\uD83C\uDDEE", + [":flag_gl:"] = "\uD83C\uDDEC\uD83C\uDDF1", + [":flag_gm:"] = "\uD83C\uDDEC\uD83C\uDDF2", + [":flag_gn:"] = "\uD83C\uDDEC\uD83C\uDDF3", + [":flag_gp:"] = "\uD83C\uDDEC\uD83C\uDDF5", + [":flag_gq:"] = "\uD83C\uDDEC\uD83C\uDDF6", + [":flag_gr:"] = "\uD83C\uDDEC\uD83C\uDDF7", + [":flag_gs:"] = "\uD83C\uDDEC\uD83C\uDDF8", + [":flag_gt:"] = "\uD83C\uDDEC\uD83C\uDDF9", + [":flag_gu:"] = "\uD83C\uDDEC\uD83C\uDDFA", + [":flag_gw:"] = "\uD83C\uDDEC\uD83C\uDDFC", + [":flag_gy:"] = "\uD83C\uDDEC\uD83C\uDDFE", + [":flag_hk:"] = "\uD83C\uDDED\uD83C\uDDF0", + [":flag_hm:"] = "\uD83C\uDDED\uD83C\uDDF2", + [":flag_hn:"] = "\uD83C\uDDED\uD83C\uDDF3", + [":flag_hr:"] = "\uD83C\uDDED\uD83C\uDDF7", + [":flag_ht:"] = "\uD83C\uDDED\uD83C\uDDF9", + [":flag_hu:"] = "\uD83C\uDDED\uD83C\uDDFA", + [":flag_ic:"] = "\uD83C\uDDEE\uD83C\uDDE8", + [":flag_id:"] = "\uD83C\uDDEE\uD83C\uDDE9", + [":flag_ie:"] = "\uD83C\uDDEE\uD83C\uDDEA", + [":flag_il:"] = "\uD83C\uDDEE\uD83C\uDDF1", + [":flag_im:"] = "\uD83C\uDDEE\uD83C\uDDF2", + [":flag_in:"] = "\uD83C\uDDEE\uD83C\uDDF3", + [":flag_io:"] = "\uD83C\uDDEE\uD83C\uDDF4", + [":flag_iq:"] = "\uD83C\uDDEE\uD83C\uDDF6", + [":flag_ir:"] = "\uD83C\uDDEE\uD83C\uDDF7", + [":flag_is:"] = "\uD83C\uDDEE\uD83C\uDDF8", + [":flag_it:"] = "\uD83C\uDDEE\uD83C\uDDF9", + [":flag_je:"] = "\uD83C\uDDEF\uD83C\uDDEA", + [":flag_jm:"] = "\uD83C\uDDEF\uD83C\uDDF2", + [":flag_jo:"] = "\uD83C\uDDEF\uD83C\uDDF4", + [":flag_jp:"] = "\uD83C\uDDEF\uD83C\uDDF5", + [":flag_ke:"] = "\uD83C\uDDF0\uD83C\uDDEA", + [":flag_kg:"] = "\uD83C\uDDF0\uD83C\uDDEC", + [":flag_kh:"] = "\uD83C\uDDF0\uD83C\uDDED", + [":flag_ki:"] = "\uD83C\uDDF0\uD83C\uDDEE", + [":flag_km:"] = "\uD83C\uDDF0\uD83C\uDDF2", + [":flag_kn:"] = "\uD83C\uDDF0\uD83C\uDDF3", + [":flag_kp:"] = "\uD83C\uDDF0\uD83C\uDDF5", + [":flag_kr:"] = "\uD83C\uDDF0\uD83C\uDDF7", + [":flag_kw:"] = "\uD83C\uDDF0\uD83C\uDDFC", + [":flag_ky:"] = "\uD83C\uDDF0\uD83C\uDDFE", + [":flag_kz:"] = "\uD83C\uDDF0\uD83C\uDDFF", + [":flag_la:"] = "\uD83C\uDDF1\uD83C\uDDE6", + [":flag_lb:"] = "\uD83C\uDDF1\uD83C\uDDE7", + [":flag_lc:"] = "\uD83C\uDDF1\uD83C\uDDE8", + [":flag_li:"] = "\uD83C\uDDF1\uD83C\uDDEE", + [":flag_lk:"] = "\uD83C\uDDF1\uD83C\uDDF0", + [":flag_lr:"] = "\uD83C\uDDF1\uD83C\uDDF7", + [":flag_ls:"] = "\uD83C\uDDF1\uD83C\uDDF8", + [":flag_lt:"] = "\uD83C\uDDF1\uD83C\uDDF9", + [":flag_lu:"] = "\uD83C\uDDF1\uD83C\uDDFA", + [":flag_lv:"] = "\uD83C\uDDF1\uD83C\uDDFB", + [":flag_ly:"] = "\uD83C\uDDF1\uD83C\uDDFE", + [":flag_ma:"] = "\uD83C\uDDF2\uD83C\uDDE6", + [":flag_mc:"] = "\uD83C\uDDF2\uD83C\uDDE8", + [":flag_md:"] = "\uD83C\uDDF2\uD83C\uDDE9", + [":flag_me:"] = "\uD83C\uDDF2\uD83C\uDDEA", + [":flag_mf:"] = "\uD83C\uDDF2\uD83C\uDDEB", + [":flag_mg:"] = "\uD83C\uDDF2\uD83C\uDDEC", + [":flag_mh:"] = "\uD83C\uDDF2\uD83C\uDDED", + [":flag_mk:"] = "\uD83C\uDDF2\uD83C\uDDF0", + [":flag_ml:"] = "\uD83C\uDDF2\uD83C\uDDF1", + [":flag_mm:"] = "\uD83C\uDDF2\uD83C\uDDF2", + [":flag_mn:"] = "\uD83C\uDDF2\uD83C\uDDF3", + [":flag_mo:"] = "\uD83C\uDDF2\uD83C\uDDF4", + [":flag_mp:"] = "\uD83C\uDDF2\uD83C\uDDF5", + [":flag_mq:"] = "\uD83C\uDDF2\uD83C\uDDF6", + [":flag_mr:"] = "\uD83C\uDDF2\uD83C\uDDF7", + [":flag_ms:"] = "\uD83C\uDDF2\uD83C\uDDF8", + [":flag_mt:"] = "\uD83C\uDDF2\uD83C\uDDF9", + [":flag_mu:"] = "\uD83C\uDDF2\uD83C\uDDFA", + [":flag_mv:"] = "\uD83C\uDDF2\uD83C\uDDFB", + [":flag_mw:"] = "\uD83C\uDDF2\uD83C\uDDFC", + [":flag_mx:"] = "\uD83C\uDDF2\uD83C\uDDFD", + [":flag_my:"] = "\uD83C\uDDF2\uD83C\uDDFE", + [":flag_mz:"] = "\uD83C\uDDF2\uD83C\uDDFF", + [":flag_na:"] = "\uD83C\uDDF3\uD83C\uDDE6", + [":flag_nc:"] = "\uD83C\uDDF3\uD83C\uDDE8", + [":flag_ne:"] = "\uD83C\uDDF3\uD83C\uDDEA", + [":flag_nf:"] = "\uD83C\uDDF3\uD83C\uDDEB", + [":flag_ng:"] = "\uD83C\uDDF3\uD83C\uDDEC", + [":flag_ni:"] = "\uD83C\uDDF3\uD83C\uDDEE", + [":flag_nl:"] = "\uD83C\uDDF3\uD83C\uDDF1", + [":flag_no:"] = "\uD83C\uDDF3\uD83C\uDDF4", + [":flag_np:"] = "\uD83C\uDDF3\uD83C\uDDF5", + [":flag_nr:"] = "\uD83C\uDDF3\uD83C\uDDF7", + [":flag_nu:"] = "\uD83C\uDDF3\uD83C\uDDFA", + [":flag_nz:"] = "\uD83C\uDDF3\uD83C\uDDFF", + [":flag_om:"] = "\uD83C\uDDF4\uD83C\uDDF2", + [":flag_pa:"] = "\uD83C\uDDF5\uD83C\uDDE6", + [":flag_pe:"] = "\uD83C\uDDF5\uD83C\uDDEA", + [":flag_pf:"] = "\uD83C\uDDF5\uD83C\uDDEB", + [":flag_pg:"] = "\uD83C\uDDF5\uD83C\uDDEC", + [":flag_ph:"] = "\uD83C\uDDF5\uD83C\uDDED", + [":flag_pk:"] = "\uD83C\uDDF5\uD83C\uDDF0", + [":flag_pl:"] = "\uD83C\uDDF5\uD83C\uDDF1", + [":flag_pm:"] = "\uD83C\uDDF5\uD83C\uDDF2", + [":flag_pn:"] = "\uD83C\uDDF5\uD83C\uDDF3", + [":flag_pr:"] = "\uD83C\uDDF5\uD83C\uDDF7", + [":flag_ps:"] = "\uD83C\uDDF5\uD83C\uDDF8", + [":flag_pt:"] = "\uD83C\uDDF5\uD83C\uDDF9", + [":flag_pw:"] = "\uD83C\uDDF5\uD83C\uDDFC", + [":flag_py:"] = "\uD83C\uDDF5\uD83C\uDDFE", + [":flag_qa:"] = "\uD83C\uDDF6\uD83C\uDDE6", + [":flag_re:"] = "\uD83C\uDDF7\uD83C\uDDEA", + [":flag_ro:"] = "\uD83C\uDDF7\uD83C\uDDF4", + [":flag_rs:"] = "\uD83C\uDDF7\uD83C\uDDF8", + [":flag_ru:"] = "\uD83C\uDDF7\uD83C\uDDFA", + [":flag_rw:"] = "\uD83C\uDDF7\uD83C\uDDFC", + [":flag_sa:"] = "\uD83C\uDDF8\uD83C\uDDE6", + [":flag_sb:"] = "\uD83C\uDDF8\uD83C\uDDE7", + [":flag_sc:"] = "\uD83C\uDDF8\uD83C\uDDE8", + [":flag_sd:"] = "\uD83C\uDDF8\uD83C\uDDE9", + [":flag_se:"] = "\uD83C\uDDF8\uD83C\uDDEA", + [":flag_sg:"] = "\uD83C\uDDF8\uD83C\uDDEC", + [":flag_sh:"] = "\uD83C\uDDF8\uD83C\uDDED", + [":flag_si:"] = "\uD83C\uDDF8\uD83C\uDDEE", + [":flag_sj:"] = "\uD83C\uDDF8\uD83C\uDDEF", + [":flag_sk:"] = "\uD83C\uDDF8\uD83C\uDDF0", + [":flag_sl:"] = "\uD83C\uDDF8\uD83C\uDDF1", + [":flag_sm:"] = "\uD83C\uDDF8\uD83C\uDDF2", + [":flag_sn:"] = "\uD83C\uDDF8\uD83C\uDDF3", + [":flag_so:"] = "\uD83C\uDDF8\uD83C\uDDF4", + [":flag_sr:"] = "\uD83C\uDDF8\uD83C\uDDF7", + [":flag_ss:"] = "\uD83C\uDDF8\uD83C\uDDF8", + [":flag_st:"] = "\uD83C\uDDF8\uD83C\uDDF9", + [":flag_sv:"] = "\uD83C\uDDF8\uD83C\uDDFB", + [":flag_sx:"] = "\uD83C\uDDF8\uD83C\uDDFD", + [":flag_sy:"] = "\uD83C\uDDF8\uD83C\uDDFE", + [":flag_sz:"] = "\uD83C\uDDF8\uD83C\uDDFF", + [":flag_ta:"] = "\uD83C\uDDF9\uD83C\uDDE6", + [":flag_tc:"] = "\uD83C\uDDF9\uD83C\uDDE8", + [":flag_td:"] = "\uD83C\uDDF9\uD83C\uDDE9", + [":flag_tf:"] = "\uD83C\uDDF9\uD83C\uDDEB", + [":flag_tg:"] = "\uD83C\uDDF9\uD83C\uDDEC", + [":flag_th:"] = "\uD83C\uDDF9\uD83C\uDDED", + [":flag_tj:"] = "\uD83C\uDDF9\uD83C\uDDEF", + [":flag_tk:"] = "\uD83C\uDDF9\uD83C\uDDF0", + [":flag_tl:"] = "\uD83C\uDDF9\uD83C\uDDF1", + [":flag_tm:"] = "\uD83C\uDDF9\uD83C\uDDF2", + [":flag_tn:"] = "\uD83C\uDDF9\uD83C\uDDF3", + [":flag_to:"] = "\uD83C\uDDF9\uD83C\uDDF4", + [":flag_tr:"] = "\uD83C\uDDF9\uD83C\uDDF7", + [":flag_tt:"] = "\uD83C\uDDF9\uD83C\uDDF9", + [":flag_tv:"] = "\uD83C\uDDF9\uD83C\uDDFB", + [":flag_tw:"] = "\uD83C\uDDF9\uD83C\uDDFC", + [":flag_tz:"] = "\uD83C\uDDF9\uD83C\uDDFF", + [":flag_ua:"] = "\uD83C\uDDFA\uD83C\uDDE6", + [":flag_ug:"] = "\uD83C\uDDFA\uD83C\uDDEC", + [":flag_um:"] = "\uD83C\uDDFA\uD83C\uDDF2", + [":flag_us:"] = "\uD83C\uDDFA\uD83C\uDDF8", + [":flag_uy:"] = "\uD83C\uDDFA\uD83C\uDDFE", + [":flag_uz:"] = "\uD83C\uDDFA\uD83C\uDDFF", + [":flag_va:"] = "\uD83C\uDDFB\uD83C\uDDE6", + [":flag_vc:"] = "\uD83C\uDDFB\uD83C\uDDE8", + [":flag_ve:"] = "\uD83C\uDDFB\uD83C\uDDEA", + [":flag_vg:"] = "\uD83C\uDDFB\uD83C\uDDEC", + [":flag_vi:"] = "\uD83C\uDDFB\uD83C\uDDEE", + [":flag_vn:"] = "\uD83C\uDDFB\uD83C\uDDF3", + [":flag_vu:"] = "\uD83C\uDDFB\uD83C\uDDFA", + [":flag_wf:"] = "\uD83C\uDDFC\uD83C\uDDEB", + [":flag_white:"] = "\uD83C\uDFF3️", + [":flag_ws:"] = "\uD83C\uDDFC\uD83C\uDDF8", + [":flag_xk:"] = "\uD83C\uDDFD\uD83C\uDDF0", + [":flag_ye:"] = "\uD83C\uDDFE\uD83C\uDDEA", + [":flag_yt:"] = "\uD83C\uDDFE\uD83C\uDDF9", + [":flag_za:"] = "\uD83C\uDDFF\uD83C\uDDE6", + [":flag_zm:"] = "\uD83C\uDDFF\uD83C\uDDF2", + [":flag_zw:"] = "\uD83C\uDDFF\uD83C\uDDFC", + [":flags:"] = "\uD83C\uDF8F", + [":flame:"] = "\uD83D\uDD25", + [":flamingo:"] = "\uD83E\uDDA9", + [":flan:"] = "\uD83C\uDF6E", + [":flashlight:"] = "\uD83D\uDD26", + [":fleur_de_lis:"] = "⚜️", + [":floppy_disk:"] = "\uD83D\uDCBE", + [":flower_playing_cards:"] = "\uD83C\uDFB4", + [":flushed:"] = "\uD83D\uDE33", + [":flying_disc:"] = "\uD83E\uDD4F", + [":flying_saucer:"] = "\uD83D\uDEF8", + [":fog:"] = "\uD83C\uDF2B️", + [":foggy:"] = "\uD83C\uDF01", + [":foot:"] = "\uD83E\uDDB6", + [":foot::skin-tone-1:"] = "\uD83E\uDDB6\uD83C\uDFFB", + [":foot::skin-tone-2:"] = "\uD83E\uDDB6\uD83C\uDFFC", + [":foot::skin-tone-3:"] = "\uD83E\uDDB6\uD83C\uDFFD", + [":foot::skin-tone-4:"] = "\uD83E\uDDB6\uD83C\uDFFE", + [":foot::skin-tone-5:"] = "\uD83E\uDDB6\uD83C\uDFFF", + [":foot_dark_skin_tone:"] = "\uD83E\uDDB6\uD83C\uDFFF", + [":foot_light_skin_tone:"] = "\uD83E\uDDB6\uD83C\uDFFB", + [":foot_medium_dark_skin_tone:"] = "\uD83E\uDDB6\uD83C\uDFFE", + [":foot_medium_light_skin_tone:"] = "\uD83E\uDDB6\uD83C\uDFFC", + [":foot_medium_skin_tone:"] = "\uD83E\uDDB6\uD83C\uDFFD", + [":foot_tone1:"] = "\uD83E\uDDB6\uD83C\uDFFB", + [":foot_tone2:"] = "\uD83E\uDDB6\uD83C\uDFFC", + [":foot_tone3:"] = "\uD83E\uDDB6\uD83C\uDFFD", + [":foot_tone4:"] = "\uD83E\uDDB6\uD83C\uDFFE", + [":foot_tone5:"] = "\uD83E\uDDB6\uD83C\uDFFF", + [":football:"] = "\uD83C\uDFC8", + [":footprints:"] = "\uD83D\uDC63", + [":fork_and_knife:"] = "\uD83C\uDF74", + [":fork_and_knife_with_plate:"] = "\uD83C\uDF7D️", + [":fork_knife_plate:"] = "\uD83C\uDF7D️", + [":fortune_cookie:"] = "\uD83E\uDD60", + [":fountain:"] = "⛲", + [":four:"] = "4️⃣", + [":four_leaf_clover:"] = "\uD83C\uDF40", + [":fox:"] = "\uD83E\uDD8A", + [":fox_face:"] = "\uD83E\uDD8A", + [":frame_photo:"] = "\uD83D\uDDBC️", + [":frame_with_picture:"] = "\uD83D\uDDBC️", + [":free:"] = "\uD83C\uDD93", + [":french_bread:"] = "\uD83E\uDD56", + [":fried_shrimp:"] = "\uD83C\uDF64", + [":fries:"] = "\uD83C\uDF5F", + [":frog:"] = "\uD83D\uDC38", + [":frowning2:"] = "☹️", + [":frowning:"] = "\uD83D\uDE26", + [":fuelpump:"] = "⛽", + [":full_moon:"] = "\uD83C\uDF15", + [":full_moon_with_face:"] = "\uD83C\uDF1D", + [":funeral_urn:"] = "⚱️", + [":game_die:"] = "\uD83C\uDFB2", + [":garlic:"] = "\uD83E\uDDC4", + [":gay_pride_flag:"] = "\uD83C\uDFF3️\u200D\uD83C\uDF08", + [":gear:"] = "⚙️", + [":gem:"] = "\uD83D\uDC8E", + [":gemini:"] = "♊", + [":genie:"] = "\uD83E\uDDDE", + [":ghost:"] = "\uD83D\uDC7B", + [":gift:"] = "\uD83C\uDF81", + [":gift_heart:"] = "\uD83D\uDC9D", + [":giraffe:"] = "\uD83E\uDD92", + [":girl:"] = "\uD83D\uDC67", + [":girl::skin-tone-1:"] = "\uD83D\uDC67\uD83C\uDFFB", + [":girl::skin-tone-2:"] = "\uD83D\uDC67\uD83C\uDFFC", + [":girl::skin-tone-3:"] = "\uD83D\uDC67\uD83C\uDFFD", + [":girl::skin-tone-4:"] = "\uD83D\uDC67\uD83C\uDFFE", + [":girl::skin-tone-5:"] = "\uD83D\uDC67\uD83C\uDFFF", + [":girl_tone1:"] = "\uD83D\uDC67\uD83C\uDFFB", + [":girl_tone2:"] = "\uD83D\uDC67\uD83C\uDFFC", + [":girl_tone3:"] = "\uD83D\uDC67\uD83C\uDFFD", + [":girl_tone4:"] = "\uD83D\uDC67\uD83C\uDFFE", + [":girl_tone5:"] = "\uD83D\uDC67\uD83C\uDFFF", + [":glass_of_milk:"] = "\uD83E\uDD5B", + [":globe_with_meridians:"] = "\uD83C\uDF10", + [":gloves:"] = "\uD83E\uDDE4", + [":goal:"] = "\uD83E\uDD45", + [":goal_net:"] = "\uD83E\uDD45", + [":goat:"] = "\uD83D\uDC10", + [":goggles:"] = "\uD83E\uDD7D", + [":golf:"] = "⛳", + [":golfer:"] = "\uD83C\uDFCC️", + [":golfer::skin-tone-1:"] = "\uD83C\uDFCC\uD83C\uDFFB", + [":golfer::skin-tone-2:"] = "\uD83C\uDFCC\uD83C\uDFFC", + [":golfer::skin-tone-3:"] = "\uD83C\uDFCC\uD83C\uDFFD", + [":golfer::skin-tone-4:"] = "\uD83C\uDFCC\uD83C\uDFFE", + [":golfer::skin-tone-5:"] = "\uD83C\uDFCC\uD83C\uDFFF", + [":gorilla:"] = "\uD83E\uDD8D", + [":grandma:"] = "\uD83D\uDC75", + [":grandma::skin-tone-1:"] = "\uD83D\uDC75\uD83C\uDFFB", + [":grandma::skin-tone-2:"] = "\uD83D\uDC75\uD83C\uDFFC", + [":grandma::skin-tone-3:"] = "\uD83D\uDC75\uD83C\uDFFD", + [":grandma::skin-tone-4:"] = "\uD83D\uDC75\uD83C\uDFFE", + [":grandma::skin-tone-5:"] = "\uD83D\uDC75\uD83C\uDFFF", + [":grandma_tone1:"] = "\uD83D\uDC75\uD83C\uDFFB", + [":grandma_tone2:"] = "\uD83D\uDC75\uD83C\uDFFC", + [":grandma_tone3:"] = "\uD83D\uDC75\uD83C\uDFFD", + [":grandma_tone4:"] = "\uD83D\uDC75\uD83C\uDFFE", + [":grandma_tone5:"] = "\uD83D\uDC75\uD83C\uDFFF", + [":grapes:"] = "\uD83C\uDF47", + [":green_apple:"] = "\uD83C\uDF4F", + [":green_book:"] = "\uD83D\uDCD7", + [":green_circle:"] = "\uD83D\uDFE2", + [":green_heart:"] = "\uD83D\uDC9A", + [":green_salad:"] = "\uD83E\uDD57", + [":green_square:"] = "\uD83D\uDFE9", + [":grey_exclamation:"] = "❕", + [":grey_question:"] = "❔", + [":grimacing:"] = "\uD83D\uDE2C", + [":grin:"] = "\uD83D\uDE01", + [":grinning:"] = "\uD83D\uDE00", + [":guard:"] = "\uD83D\uDC82", + [":guard::skin-tone-1:"] = "\uD83D\uDC82\uD83C\uDFFB", + [":guard::skin-tone-2:"] = "\uD83D\uDC82\uD83C\uDFFC", + [":guard::skin-tone-3:"] = "\uD83D\uDC82\uD83C\uDFFD", + [":guard::skin-tone-4:"] = "\uD83D\uDC82\uD83C\uDFFE", + [":guard::skin-tone-5:"] = "\uD83D\uDC82\uD83C\uDFFF", + [":guard_tone1:"] = "\uD83D\uDC82\uD83C\uDFFB", + [":guard_tone2:"] = "\uD83D\uDC82\uD83C\uDFFC", + [":guard_tone3:"] = "\uD83D\uDC82\uD83C\uDFFD", + [":guard_tone4:"] = "\uD83D\uDC82\uD83C\uDFFE", + [":guard_tone5:"] = "\uD83D\uDC82\uD83C\uDFFF", + [":guardsman:"] = "\uD83D\uDC82", + [":guardsman::skin-tone-1:"] = "\uD83D\uDC82\uD83C\uDFFB", + [":guardsman::skin-tone-2:"] = "\uD83D\uDC82\uD83C\uDFFC", + [":guardsman::skin-tone-3:"] = "\uD83D\uDC82\uD83C\uDFFD", + [":guardsman::skin-tone-4:"] = "\uD83D\uDC82\uD83C\uDFFE", + [":guardsman::skin-tone-5:"] = "\uD83D\uDC82\uD83C\uDFFF", + [":guardsman_tone1:"] = "\uD83D\uDC82\uD83C\uDFFB", + [":guardsman_tone2:"] = "\uD83D\uDC82\uD83C\uDFFC", + [":guardsman_tone3:"] = "\uD83D\uDC82\uD83C\uDFFD", + [":guardsman_tone4:"] = "\uD83D\uDC82\uD83C\uDFFE", + [":guardsman_tone5:"] = "\uD83D\uDC82\uD83C\uDFFF", + [":guide_dog:"] = "\uD83E\uDDAE", + [":guitar:"] = "\uD83C\uDFB8", + [":gun:"] = "\uD83D\uDD2B", + [":haircut:"] = "\uD83D\uDC87", + [":haircut::skin-tone-1:"] = "\uD83D\uDC87\uD83C\uDFFB", + [":haircut::skin-tone-2:"] = "\uD83D\uDC87\uD83C\uDFFC", + [":haircut::skin-tone-3:"] = "\uD83D\uDC87\uD83C\uDFFD", + [":haircut::skin-tone-4:"] = "\uD83D\uDC87\uD83C\uDFFE", + [":haircut::skin-tone-5:"] = "\uD83D\uDC87\uD83C\uDFFF", + [":haircut_tone1:"] = "\uD83D\uDC87\uD83C\uDFFB", + [":haircut_tone2:"] = "\uD83D\uDC87\uD83C\uDFFC", + [":haircut_tone3:"] = "\uD83D\uDC87\uD83C\uDFFD", + [":haircut_tone4:"] = "\uD83D\uDC87\uD83C\uDFFE", + [":haircut_tone5:"] = "\uD83D\uDC87\uD83C\uDFFF", + [":hamburger:"] = "\uD83C\uDF54", + [":hammer:"] = "\uD83D\uDD28", + [":hammer_and_pick:"] = "⚒️", + [":hammer_and_wrench:"] = "\uD83D\uDEE0️", + [":hammer_pick:"] = "⚒️", + [":hamster:"] = "\uD83D\uDC39", + [":hand_splayed:"] = "\uD83D\uDD90️", + [":hand_splayed::skin-tone-1:"] = "\uD83D\uDD90\uD83C\uDFFB", + [":hand_splayed::skin-tone-2:"] = "\uD83D\uDD90\uD83C\uDFFC", + [":hand_splayed::skin-tone-3:"] = "\uD83D\uDD90\uD83C\uDFFD", + [":hand_splayed::skin-tone-4:"] = "\uD83D\uDD90\uD83C\uDFFE", + [":hand_splayed::skin-tone-5:"] = "\uD83D\uDD90\uD83C\uDFFF", + [":hand_splayed_tone1:"] = "\uD83D\uDD90\uD83C\uDFFB", + [":hand_splayed_tone2:"] = "\uD83D\uDD90\uD83C\uDFFC", + [":hand_splayed_tone3:"] = "\uD83D\uDD90\uD83C\uDFFD", + [":hand_splayed_tone4:"] = "\uD83D\uDD90\uD83C\uDFFE", + [":hand_splayed_tone5:"] = "\uD83D\uDD90\uD83C\uDFFF", + [":hand_with_index_and_middle_finger_crossed:"] = "\uD83E\uDD1E", + [":hand_with_index_and_middle_finger_crossed::skin-tone-1:"] = "\uD83E\uDD1E\uD83C\uDFFB", + [":hand_with_index_and_middle_finger_crossed::skin-tone-2:"] = "\uD83E\uDD1E\uD83C\uDFFC", + [":hand_with_index_and_middle_finger_crossed::skin-tone-3:"] = "\uD83E\uDD1E\uD83C\uDFFD", + [":hand_with_index_and_middle_finger_crossed::skin-tone-4:"] = "\uD83E\uDD1E\uD83C\uDFFE", + [":hand_with_index_and_middle_finger_crossed::skin-tone-5:"] = "\uD83E\uDD1E\uD83C\uDFFF", + [":hand_with_index_and_middle_fingers_crossed_tone1:"] = "\uD83E\uDD1E\uD83C\uDFFB", + [":hand_with_index_and_middle_fingers_crossed_tone2:"] = "\uD83E\uDD1E\uD83C\uDFFC", + [":hand_with_index_and_middle_fingers_crossed_tone3:"] = "\uD83E\uDD1E\uD83C\uDFFD", + [":hand_with_index_and_middle_fingers_crossed_tone4:"] = "\uD83E\uDD1E\uD83C\uDFFE", + [":hand_with_index_and_middle_fingers_crossed_tone5:"] = "\uD83E\uDD1E\uD83C\uDFFF", + [":handbag:"] = "\uD83D\uDC5C", + [":handball:"] = "\uD83E\uDD3E", + [":handball::skin-tone-1:"] = "\uD83E\uDD3E\uD83C\uDFFB", + [":handball::skin-tone-2:"] = "\uD83E\uDD3E\uD83C\uDFFC", + [":handball::skin-tone-3:"] = "\uD83E\uDD3E\uD83C\uDFFD", + [":handball::skin-tone-4:"] = "\uD83E\uDD3E\uD83C\uDFFE", + [":handball::skin-tone-5:"] = "\uD83E\uDD3E\uD83C\uDFFF", + [":handball_tone1:"] = "\uD83E\uDD3E\uD83C\uDFFB", + [":handball_tone2:"] = "\uD83E\uDD3E\uD83C\uDFFC", + [":handball_tone3:"] = "\uD83E\uDD3E\uD83C\uDFFD", + [":handball_tone4:"] = "\uD83E\uDD3E\uD83C\uDFFE", + [":handball_tone5:"] = "\uD83E\uDD3E\uD83C\uDFFF", + [":handshake:"] = "\uD83E\uDD1D", + [":hankey:"] = "\uD83D\uDCA9", + [":hash:"] = "#️⃣", + [":hatched_chick:"] = "\uD83D\uDC25", + [":hatching_chick:"] = "\uD83D\uDC23", + [":head_bandage:"] = "\uD83E\uDD15", + [":headphones:"] = "\uD83C\uDFA7", + [":hear_no_evil:"] = "\uD83D\uDE49", + [":heart:"] = "❤️", + [":heart_decoration:"] = "\uD83D\uDC9F", + [":heart_exclamation:"] = "❣️", + [":heart_eyes:"] = "\uD83D\uDE0D", + [":heart_eyes_cat:"] = "\uD83D\uDE3B", + [":heartbeat:"] = "\uD83D\uDC93", + [":heartpulse:"] = "\uD83D\uDC97", + [":hearts:"] = "♥️", + [":heavy_check_mark:"] = "✔️", + [":heavy_division_sign:"] = "➗", + [":heavy_dollar_sign:"] = "\uD83D\uDCB2", + [":heavy_heart_exclamation_mark_ornament:"] = "❣️", + [":heavy_minus_sign:"] = "➖", + [":heavy_multiplication_x:"] = "✖️", + [":heavy_plus_sign:"] = "➕", + [":hedgehog:"] = "\uD83E\uDD94", + [":helicopter:"] = "\uD83D\uDE81", + [":helmet_with_cross:"] = "⛑️", + [":helmet_with_white_cross:"] = "⛑️", + [":herb:"] = "\uD83C\uDF3F", + [":hibiscus:"] = "\uD83C\uDF3A", + [":high_brightness:"] = "\uD83D\uDD06", + [":high_heel:"] = "\uD83D\uDC60", + [":hiking_boot:"] = "\uD83E\uDD7E", + [":hindu_temple:"] = "\uD83D\uDED5", + [":hippopotamus:"] = "\uD83E\uDD9B", + [":hockey:"] = "\uD83C\uDFD2", + [":hole:"] = "\uD83D\uDD73️", + [":homes:"] = "\uD83C\uDFD8️", + [":honey_pot:"] = "\uD83C\uDF6F", + [":horse:"] = "\uD83D\uDC34", + [":horse_racing:"] = "\uD83C\uDFC7", + [":horse_racing::skin-tone-1:"] = "\uD83C\uDFC7\uD83C\uDFFB", + [":horse_racing::skin-tone-2:"] = "\uD83C\uDFC7\uD83C\uDFFC", + [":horse_racing::skin-tone-3:"] = "\uD83C\uDFC7\uD83C\uDFFD", + [":horse_racing::skin-tone-4:"] = "\uD83C\uDFC7\uD83C\uDFFE", + [":horse_racing::skin-tone-5:"] = "\uD83C\uDFC7\uD83C\uDFFF", + [":horse_racing_tone1:"] = "\uD83C\uDFC7\uD83C\uDFFB", + [":horse_racing_tone2:"] = "\uD83C\uDFC7\uD83C\uDFFC", + [":horse_racing_tone3:"] = "\uD83C\uDFC7\uD83C\uDFFD", + [":horse_racing_tone4:"] = "\uD83C\uDFC7\uD83C\uDFFE", + [":horse_racing_tone5:"] = "\uD83C\uDFC7\uD83C\uDFFF", + [":hospital:"] = "\uD83C\uDFE5", + [":hot_dog:"] = "\uD83C\uDF2D", + [":hot_face:"] = "\uD83E\uDD75", + [":hot_pepper:"] = "\uD83C\uDF36️", + [":hotdog:"] = "\uD83C\uDF2D", + [":hotel:"] = "\uD83C\uDFE8", + [":hotsprings:"] = "♨️", + [":hourglass:"] = "⌛", + [":hourglass_flowing_sand:"] = "⏳", + [":house:"] = "\uD83C\uDFE0", + [":house_abandoned:"] = "\uD83C\uDFDA️", + [":house_buildings:"] = "\uD83C\uDFD8️", + [":house_with_garden:"] = "\uD83C\uDFE1", + [":hugging:"] = "\uD83E\uDD17", + [":hugging_face:"] = "\uD83E\uDD17", + [":hushed:"] = "\uD83D\uDE2F", + [":ice_cream:"] = "\uD83C\uDF68", + [":ice_cube:"] = "\uD83E\uDDCA", + [":ice_skate:"] = "⛸️", + [":icecream:"] = "\uD83C\uDF66", + [":id:"] = "\uD83C\uDD94", + [":ideograph_advantage:"] = "\uD83C\uDE50", + [":imp:"] = "\uD83D\uDC7F", + [":inbox_tray:"] = "\uD83D\uDCE5", + [":incoming_envelope:"] = "\uD83D\uDCE8", + [":infinity:"] = "♾️", + [":information_desk_person:"] = "\uD83D\uDC81", + [":information_desk_person::skin-tone-1:"] = "\uD83D\uDC81\uD83C\uDFFB", + [":information_desk_person::skin-tone-2:"] = "\uD83D\uDC81\uD83C\uDFFC", + [":information_desk_person::skin-tone-3:"] = "\uD83D\uDC81\uD83C\uDFFD", + [":information_desk_person::skin-tone-4:"] = "\uD83D\uDC81\uD83C\uDFFE", + [":information_desk_person::skin-tone-5:"] = "\uD83D\uDC81\uD83C\uDFFF", + [":information_desk_person_tone1:"] = "\uD83D\uDC81\uD83C\uDFFB", + [":information_desk_person_tone2:"] = "\uD83D\uDC81\uD83C\uDFFC", + [":information_desk_person_tone3:"] = "\uD83D\uDC81\uD83C\uDFFD", + [":information_desk_person_tone4:"] = "\uD83D\uDC81\uD83C\uDFFE", + [":information_desk_person_tone5:"] = "\uD83D\uDC81\uD83C\uDFFF", + [":information_source:"] = "ℹ️", + [":innocent:"] = "\uD83D\uDE07", + [":interrobang:"] = "⁉️", + [":iphone:"] = "\uD83D\uDCF1", + [":island:"] = "\uD83C\uDFDD️", + [":izakaya_lantern:"] = "\uD83C\uDFEE", + [":jack_o_lantern:"] = "\uD83C\uDF83", + [":japan:"] = "\uD83D\uDDFE", + [":japanese_castle:"] = "\uD83C\uDFEF", + [":japanese_goblin:"] = "\uD83D\uDC7A", + [":japanese_ogre:"] = "\uD83D\uDC79", + [":jeans:"] = "\uD83D\uDC56", + [":jigsaw:"] = "\uD83E\uDDE9", + [":joy:"] = "\uD83D\uDE02", + [":joy_cat:"] = "\uD83D\uDE39", + [":joystick:"] = "\uD83D\uDD79️", + [":juggler:"] = "\uD83E\uDD39", + [":juggler::skin-tone-1:"] = "\uD83E\uDD39\uD83C\uDFFB", + [":juggler::skin-tone-2:"] = "\uD83E\uDD39\uD83C\uDFFC", + [":juggler::skin-tone-3:"] = "\uD83E\uDD39\uD83C\uDFFD", + [":juggler::skin-tone-4:"] = "\uD83E\uDD39\uD83C\uDFFE", + [":juggler::skin-tone-5:"] = "\uD83E\uDD39\uD83C\uDFFF", + [":juggler_tone1:"] = "\uD83E\uDD39\uD83C\uDFFB", + [":juggler_tone2:"] = "\uD83E\uDD39\uD83C\uDFFC", + [":juggler_tone3:"] = "\uD83E\uDD39\uD83C\uDFFD", + [":juggler_tone4:"] = "\uD83E\uDD39\uD83C\uDFFE", + [":juggler_tone5:"] = "\uD83E\uDD39\uD83C\uDFFF", + [":juggling:"] = "\uD83E\uDD39", + [":juggling::skin-tone-1:"] = "\uD83E\uDD39\uD83C\uDFFB", + [":juggling::skin-tone-2:"] = "\uD83E\uDD39\uD83C\uDFFC", + [":juggling::skin-tone-3:"] = "\uD83E\uDD39\uD83C\uDFFD", + [":juggling::skin-tone-4:"] = "\uD83E\uDD39\uD83C\uDFFE", + [":juggling::skin-tone-5:"] = "\uD83E\uDD39\uD83C\uDFFF", + [":juggling_tone1:"] = "\uD83E\uDD39\uD83C\uDFFB", + [":juggling_tone2:"] = "\uD83E\uDD39\uD83C\uDFFC", + [":juggling_tone3:"] = "\uD83E\uDD39\uD83C\uDFFD", + [":juggling_tone4:"] = "\uD83E\uDD39\uD83C\uDFFE", + [":juggling_tone5:"] = "\uD83E\uDD39\uD83C\uDFFF", + [":kaaba:"] = "\uD83D\uDD4B", + [":kangaroo:"] = "\uD83E\uDD98", + [":karate_uniform:"] = "\uD83E\uDD4B", + [":kayak:"] = "\uD83D\uDEF6", + [":key2:"] = "\uD83D\uDDDD️", + [":key:"] = "\uD83D\uDD11", + [":keyboard:"] = "⌨️", + [":keycap_asterisk:"] = "*️⃣", + [":keycap_ten:"] = "\uD83D\uDD1F", + [":kimono:"] = "\uD83D\uDC58", + [":kiss:"] = "\uD83D\uDC8B", + [":kiss_mm:"] = "\uD83D\uDC68\u200D❤️\u200D\uD83D\uDC8B\u200D\uD83D\uDC68", + [":kiss_woman_man:"] = "\uD83D\uDC69\u200D❤️\u200D\uD83D\uDC8B\u200D\uD83D\uDC68", + [":kiss_ww:"] = "\uD83D\uDC69\u200D❤️\u200D\uD83D\uDC8B\u200D\uD83D\uDC69", + [":kissing:"] = "\uD83D\uDE17", + [":kissing_cat:"] = "\uD83D\uDE3D", + [":kissing_closed_eyes:"] = "\uD83D\uDE1A", + [":kissing_heart:"] = "\uD83D\uDE18", + [":kissing_smiling_eyes:"] = "\uD83D\uDE19", + [":kite:"] = "\uD83E\uDE81", + [":kiwi:"] = "\uD83E\uDD5D", + [":kiwifruit:"] = "\uD83E\uDD5D", + [":knife:"] = "\uD83D\uDD2A", + [":koala:"] = "\uD83D\uDC28", + [":koko:"] = "\uD83C\uDE01", + [":knot:"] = "\uD83E\uDEA2", + [":lab_coat:"] = "\uD83E\uDD7C", + [":label:"] = "\uD83C\uDFF7️", + [":lacrosse:"] = "\uD83E\uDD4D", + [":large_blue_diamond:"] = "\uD83D\uDD37", + [":large_orange_diamond:"] = "\uD83D\uDD36", + [":last_quarter_moon:"] = "\uD83C\uDF17", + [":last_quarter_moon_with_face:"] = "\uD83C\uDF1C", + [":latin_cross:"] = "✝️", + [":laughing:"] = "\uD83D\uDE06", + [":leafy_green:"] = "\uD83E\uDD6C", + [":leaves:"] = "\uD83C\uDF43", + [":ledger:"] = "\uD83D\uDCD2", + [":left_facing_fist:"] = "\uD83E\uDD1B", + [":left_facing_fist::skin-tone-1:"] = "\uD83E\uDD1B\uD83C\uDFFB", + [":left_facing_fist::skin-tone-2:"] = "\uD83E\uDD1B\uD83C\uDFFC", + [":left_facing_fist::skin-tone-3:"] = "\uD83E\uDD1B\uD83C\uDFFD", + [":left_facing_fist::skin-tone-4:"] = "\uD83E\uDD1B\uD83C\uDFFE", + [":left_facing_fist::skin-tone-5:"] = "\uD83E\uDD1B\uD83C\uDFFF", + [":left_facing_fist_tone1:"] = "\uD83E\uDD1B\uD83C\uDFFB", + [":left_facing_fist_tone2:"] = "\uD83E\uDD1B\uD83C\uDFFC", + [":left_facing_fist_tone3:"] = "\uD83E\uDD1B\uD83C\uDFFD", + [":left_facing_fist_tone4:"] = "\uD83E\uDD1B\uD83C\uDFFE", + [":left_facing_fist_tone5:"] = "\uD83E\uDD1B\uD83C\uDFFF", + [":left_fist:"] = "\uD83E\uDD1B", + [":left_fist::skin-tone-1:"] = "\uD83E\uDD1B\uD83C\uDFFB", + [":left_fist::skin-tone-2:"] = "\uD83E\uDD1B\uD83C\uDFFC", + [":left_fist::skin-tone-3:"] = "\uD83E\uDD1B\uD83C\uDFFD", + [":left_fist::skin-tone-4:"] = "\uD83E\uDD1B\uD83C\uDFFE", + [":left_fist::skin-tone-5:"] = "\uD83E\uDD1B\uD83C\uDFFF", + [":left_fist_tone1:"] = "\uD83E\uDD1B\uD83C\uDFFB", + [":left_fist_tone2:"] = "\uD83E\uDD1B\uD83C\uDFFC", + [":left_fist_tone3:"] = "\uD83E\uDD1B\uD83C\uDFFD", + [":left_fist_tone4:"] = "\uD83E\uDD1B\uD83C\uDFFE", + [":left_fist_tone5:"] = "\uD83E\uDD1B\uD83C\uDFFF", + [":left_luggage:"] = "\uD83D\uDEC5", + [":left_right_arrow:"] = "↔️", + [":left_speech_bubble:"] = "\uD83D\uDDE8️", + [":leftwards_arrow_with_hook:"] = "↩️", + [":leg:"] = "\uD83E\uDDB5", + [":leg::skin-tone-1:"] = "\uD83E\uDDB5\uD83C\uDFFB", + [":leg::skin-tone-2:"] = "\uD83E\uDDB5\uD83C\uDFFC", + [":leg::skin-tone-3:"] = "\uD83E\uDDB5\uD83C\uDFFD", + [":leg::skin-tone-4:"] = "\uD83E\uDDB5\uD83C\uDFFE", + [":leg::skin-tone-5:"] = "\uD83E\uDDB5\uD83C\uDFFF", + [":leg_dark_skin_tone:"] = "\uD83E\uDDB5\uD83C\uDFFF", + [":leg_light_skin_tone:"] = "\uD83E\uDDB5\uD83C\uDFFB", + [":leg_medium_dark_skin_tone:"] = "\uD83E\uDDB5\uD83C\uDFFE", + [":leg_medium_light_skin_tone:"] = "\uD83E\uDDB5\uD83C\uDFFC", + [":leg_medium_skin_tone:"] = "\uD83E\uDDB5\uD83C\uDFFD", + [":leg_tone1:"] = "\uD83E\uDDB5\uD83C\uDFFB", + [":leg_tone2:"] = "\uD83E\uDDB5\uD83C\uDFFC", + [":leg_tone3:"] = "\uD83E\uDDB5\uD83C\uDFFD", + [":leg_tone4:"] = "\uD83E\uDDB5\uD83C\uDFFE", + [":leg_tone5:"] = "\uD83E\uDDB5\uD83C\uDFFF", + [":lemon:"] = "\uD83C\uDF4B", + [":leo:"] = "♌", + [":leopard:"] = "\uD83D\uDC06", + [":level_slider:"] = "\uD83C\uDF9A️", + [":levitate:"] = "\uD83D\uDD74️", + [":levitate::skin-tone-1:"] = "\uD83D\uDD74\uD83C\uDFFB", + [":levitate::skin-tone-2:"] = "\uD83D\uDD74\uD83C\uDFFC", + [":levitate::skin-tone-3:"] = "\uD83D\uDD74\uD83C\uDFFD", + [":levitate::skin-tone-4:"] = "\uD83D\uDD74\uD83C\uDFFE", + [":levitate::skin-tone-5:"] = "\uD83D\uDD74\uD83C\uDFFF", + [":levitate_tone1:"] = "\uD83D\uDD74\uD83C\uDFFB", + [":levitate_tone2:"] = "\uD83D\uDD74\uD83C\uDFFC", + [":levitate_tone3:"] = "\uD83D\uDD74\uD83C\uDFFD", + [":levitate_tone4:"] = "\uD83D\uDD74\uD83C\uDFFE", + [":levitate_tone5:"] = "\uD83D\uDD74\uD83C\uDFFF", + [":liar:"] = "\uD83E\uDD25", + [":libra:"] = "♎", + [":lifter:"] = "\uD83C\uDFCB️", + [":lifter::skin-tone-1:"] = "\uD83C\uDFCB\uD83C\uDFFB", + [":lifter::skin-tone-2:"] = "\uD83C\uDFCB\uD83C\uDFFC", + [":lifter::skin-tone-3:"] = "\uD83C\uDFCB\uD83C\uDFFD", + [":lifter::skin-tone-4:"] = "\uD83C\uDFCB\uD83C\uDFFE", + [":lifter::skin-tone-5:"] = "\uD83C\uDFCB\uD83C\uDFFF", + [":lifter_tone1:"] = "\uD83C\uDFCB\uD83C\uDFFB", + [":lifter_tone2:"] = "\uD83C\uDFCB\uD83C\uDFFC", + [":lifter_tone3:"] = "\uD83C\uDFCB\uD83C\uDFFD", + [":lifter_tone4:"] = "\uD83C\uDFCB\uD83C\uDFFE", + [":lifter_tone5:"] = "\uD83C\uDFCB\uD83C\uDFFF", + [":light_rail:"] = "\uD83D\uDE88", + [":link:"] = "\uD83D\uDD17", + [":linked_paperclips:"] = "\uD83D\uDD87️", + [":lion:"] = "\uD83E\uDD81", + [":lion_face:"] = "\uD83E\uDD81", + [":lips:"] = "\uD83D\uDC44", + [":lipstick:"] = "\uD83D\uDC84", + [":lizard:"] = "\uD83E\uDD8E", + [":llama:"] = "\uD83E\uDD99", + [":lobster:"] = "\uD83E\uDD9E", + [":lock:"] = "\uD83D\uDD12", + [":lock_with_ink_pen:"] = "\uD83D\uDD0F", + [":lollipop:"] = "\uD83C\uDF6D", + [":loop:"] = "➿", + [":loud_sound:"] = "\uD83D\uDD0A", + [":loudspeaker:"] = "\uD83D\uDCE2", + [":love_hotel:"] = "\uD83C\uDFE9", + [":love_letter:"] = "\uD83D\uDC8C", + [":love_you_gesture:"] = "\uD83E\uDD1F", + [":love_you_gesture::skin-tone-1:"] = "\uD83E\uDD1F\uD83C\uDFFB", + [":love_you_gesture::skin-tone-2:"] = "\uD83E\uDD1F\uD83C\uDFFC", + [":love_you_gesture::skin-tone-3:"] = "\uD83E\uDD1F\uD83C\uDFFD", + [":love_you_gesture::skin-tone-4:"] = "\uD83E\uDD1F\uD83C\uDFFE", + [":love_you_gesture::skin-tone-5:"] = "\uD83E\uDD1F\uD83C\uDFFF", + [":love_you_gesture_dark_skin_tone:"] = "\uD83E\uDD1F\uD83C\uDFFF", + [":love_you_gesture_light_skin_tone:"] = "\uD83E\uDD1F\uD83C\uDFFB", + [":love_you_gesture_medium_dark_skin_tone:"] = "\uD83E\uDD1F\uD83C\uDFFE", + [":love_you_gesture_medium_light_skin_tone:"] = "\uD83E\uDD1F\uD83C\uDFFC", + [":love_you_gesture_medium_skin_tone:"] = "\uD83E\uDD1F\uD83C\uDFFD", + [":love_you_gesture_tone1:"] = "\uD83E\uDD1F\uD83C\uDFFB", + [":love_you_gesture_tone2:"] = "\uD83E\uDD1F\uD83C\uDFFC", + [":love_you_gesture_tone3:"] = "\uD83E\uDD1F\uD83C\uDFFD", + [":love_you_gesture_tone4:"] = "\uD83E\uDD1F\uD83C\uDFFE", + [":love_you_gesture_tone5:"] = "\uD83E\uDD1F\uD83C\uDFFF", + [":low_brightness:"] = "\uD83D\uDD05", + [":lower_left_ballpoint_pen:"] = "\uD83D\uDD8A️", + [":lower_left_crayon:"] = "\uD83D\uDD8D️", + [":lower_left_fountain_pen:"] = "\uD83D\uDD8B️", + [":lower_left_paintbrush:"] = "\uD83D\uDD8C️", + [":luggage:"] = "\uD83E\uDDF3", + [":lying_face:"] = "\uD83E\uDD25", + [":m:"] = "Ⓜ️", + [":mag:"] = "\uD83D\uDD0D", + [":mag_right:"] = "\uD83D\uDD0E", + [":mage:"] = "\uD83E\uDDD9", + [":mage::skin-tone-1:"] = "\uD83E\uDDD9\uD83C\uDFFB", + [":mage::skin-tone-2:"] = "\uD83E\uDDD9\uD83C\uDFFC", + [":mage::skin-tone-3:"] = "\uD83E\uDDD9\uD83C\uDFFD", + [":mage::skin-tone-4:"] = "\uD83E\uDDD9\uD83C\uDFFE", + [":mage::skin-tone-5:"] = "\uD83E\uDDD9\uD83C\uDFFF", + [":mage_dark_skin_tone:"] = "\uD83E\uDDD9\uD83C\uDFFF", + [":mage_light_skin_tone:"] = "\uD83E\uDDD9\uD83C\uDFFB", + [":mage_medium_dark_skin_tone:"] = "\uD83E\uDDD9\uD83C\uDFFE", + [":mage_medium_light_skin_tone:"] = "\uD83E\uDDD9\uD83C\uDFFC", + [":mage_medium_skin_tone:"] = "\uD83E\uDDD9\uD83C\uDFFD", + [":mage_tone1:"] = "\uD83E\uDDD9\uD83C\uDFFB", + [":mage_tone2:"] = "\uD83E\uDDD9\uD83C\uDFFC", + [":mage_tone3:"] = "\uD83E\uDDD9\uD83C\uDFFD", + [":mage_tone4:"] = "\uD83E\uDDD9\uD83C\uDFFE", + [":mage_tone5:"] = "\uD83E\uDDD9\uD83C\uDFFF", + [":magnet:"] = "\uD83E\uDDF2", + [":mahjong:"] = "\uD83C\uDC04", + [":mailbox:"] = "\uD83D\uDCEB", + [":mailbox_closed:"] = "\uD83D\uDCEA", + [":mailbox_with_mail:"] = "\uD83D\uDCEC", + [":mailbox_with_no_mail:"] = "\uD83D\uDCED", + [":male_dancer:"] = "\uD83D\uDD7A", + [":male_dancer::skin-tone-1:"] = "\uD83D\uDD7A\uD83C\uDFFB", + [":male_dancer::skin-tone-2:"] = "\uD83D\uDD7A\uD83C\uDFFC", + [":male_dancer::skin-tone-3:"] = "\uD83D\uDD7A\uD83C\uDFFD", + [":male_dancer::skin-tone-4:"] = "\uD83D\uDD7A\uD83C\uDFFE", + [":male_dancer::skin-tone-5:"] = "\uD83D\uDD7A\uD83C\uDFFF", + [":male_dancer_tone1:"] = "\uD83D\uDD7A\uD83C\uDFFB", + [":male_dancer_tone2:"] = "\uD83D\uDD7A\uD83C\uDFFC", + [":male_dancer_tone3:"] = "\uD83D\uDD7A\uD83C\uDFFD", + [":male_dancer_tone4:"] = "\uD83D\uDD7A\uD83C\uDFFE", + [":male_dancer_tone5:"] = "\uD83D\uDD7A\uD83C\uDFFF", + [":male_sign:"] = "♂️", + [":man:"] = "\uD83D\uDC68", + [":man::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB", + [":man::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC", + [":man::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD", + [":man::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE", + [":man::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF", + [":man_artist:"] = "\uD83D\uDC68\u200D\uD83C\uDFA8", + [":man_artist::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDFA8", + [":man_artist::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDFA8", + [":man_artist::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDFA8", + [":man_artist::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDFA8", + [":man_artist::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDFA8", + [":man_artist_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDFA8", + [":man_artist_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDFA8", + [":man_artist_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDFA8", + [":man_artist_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDFA8", + [":man_artist_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDFA8", + [":man_artist_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDFA8", + [":man_artist_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDFA8", + [":man_artist_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDFA8", + [":man_artist_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDFA8", + [":man_artist_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDFA8", + [":man_astronaut:"] = "\uD83D\uDC68\u200D\uD83D\uDE80", + [":man_astronaut::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDE80", + [":man_astronaut::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDE80", + [":man_astronaut::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDE80", + [":man_astronaut::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDE80", + [":man_astronaut::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDE80", + [":man_astronaut_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDE80", + [":man_astronaut_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDE80", + [":man_astronaut_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDE80", + [":man_astronaut_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDE80", + [":man_astronaut_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDE80", + [":man_astronaut_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDE80", + [":man_astronaut_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDE80", + [":man_astronaut_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDE80", + [":man_astronaut_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDE80", + [":man_astronaut_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDE80", + [":man_bald:"] = "\uD83D\uDC68\u200D\uD83E\uDDB2", + [":man_bald::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDB2", + [":man_bald::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDB2", + [":man_bald::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDB2", + [":man_bald::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDB2", + [":man_bald::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDB2", + [":man_bald_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDB2", + [":man_bald_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDB2", + [":man_bald_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDB2", + [":man_bald_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDB2", + [":man_bald_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDB2", + [":man_bald_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDB2", + [":man_bald_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDB2", + [":man_bald_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDB2", + [":man_bald_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDB2", + [":man_bald_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDB2", + [":man_biking:"] = "\uD83D\uDEB4\u200D♂️", + [":man_biking::skin-tone-1:"] = "\uD83D\uDEB4\uD83C\uDFFB\u200D♂️", + [":man_biking::skin-tone-2:"] = "\uD83D\uDEB4\uD83C\uDFFC\u200D♂️", + [":man_biking::skin-tone-3:"] = "\uD83D\uDEB4\uD83C\uDFFD\u200D♂️", + [":man_biking::skin-tone-4:"] = "\uD83D\uDEB4\uD83C\uDFFE\u200D♂️", + [":man_biking::skin-tone-5:"] = "\uD83D\uDEB4\uD83C\uDFFF\u200D♂️", + [":man_biking_dark_skin_tone:"] = "\uD83D\uDEB4\uD83C\uDFFF\u200D♂️", + [":man_biking_light_skin_tone:"] = "\uD83D\uDEB4\uD83C\uDFFB\u200D♂️", + [":man_biking_medium_dark_skin_tone:"] = "\uD83D\uDEB4\uD83C\uDFFE\u200D♂️", + [":man_biking_medium_light_skin_tone:"] = "\uD83D\uDEB4\uD83C\uDFFC\u200D♂️", + [":man_biking_medium_skin_tone:"] = "\uD83D\uDEB4\uD83C\uDFFD\u200D♂️", + [":man_biking_tone1:"] = "\uD83D\uDEB4\uD83C\uDFFB\u200D♂️", + [":man_biking_tone2:"] = "\uD83D\uDEB4\uD83C\uDFFC\u200D♂️", + [":man_biking_tone3:"] = "\uD83D\uDEB4\uD83C\uDFFD\u200D♂️", + [":man_biking_tone4:"] = "\uD83D\uDEB4\uD83C\uDFFE\u200D♂️", + [":man_biking_tone5:"] = "\uD83D\uDEB4\uD83C\uDFFF\u200D♂️", + [":man_bouncing_ball:"] = "⛹️\u200D♂️", + [":man_bouncing_ball::skin-tone-1:"] = "⛹\uD83C\uDFFB\u200D♂️", + [":man_bouncing_ball::skin-tone-2:"] = "⛹\uD83C\uDFFC\u200D♂️", + [":man_bouncing_ball::skin-tone-3:"] = "⛹\uD83C\uDFFD\u200D♂️", + [":man_bouncing_ball::skin-tone-4:"] = "⛹\uD83C\uDFFE\u200D♂️", + [":man_bouncing_ball::skin-tone-5:"] = "⛹\uD83C\uDFFF\u200D♂️", + [":man_bouncing_ball_dark_skin_tone:"] = "⛹\uD83C\uDFFF\u200D♂️", + [":man_bouncing_ball_light_skin_tone:"] = "⛹\uD83C\uDFFB\u200D♂️", + [":man_bouncing_ball_medium_dark_skin_tone:"] = "⛹\uD83C\uDFFE\u200D♂️", + [":man_bouncing_ball_medium_light_skin_tone:"] = "⛹\uD83C\uDFFC\u200D♂️", + [":man_bouncing_ball_medium_skin_tone:"] = "⛹\uD83C\uDFFD\u200D♂️", + [":man_bouncing_ball_tone1:"] = "⛹\uD83C\uDFFB\u200D♂️", + [":man_bouncing_ball_tone2:"] = "⛹\uD83C\uDFFC\u200D♂️", + [":man_bouncing_ball_tone3:"] = "⛹\uD83C\uDFFD\u200D♂️", + [":man_bouncing_ball_tone4:"] = "⛹\uD83C\uDFFE\u200D♂️", + [":man_bouncing_ball_tone5:"] = "⛹\uD83C\uDFFF\u200D♂️", + [":man_bowing:"] = "\uD83D\uDE47\u200D♂️", + [":man_bowing::skin-tone-1:"] = "\uD83D\uDE47\uD83C\uDFFB\u200D♂️", + [":man_bowing::skin-tone-2:"] = "\uD83D\uDE47\uD83C\uDFFC\u200D♂️", + [":man_bowing::skin-tone-3:"] = "\uD83D\uDE47\uD83C\uDFFD\u200D♂️", + [":man_bowing::skin-tone-4:"] = "\uD83D\uDE47\uD83C\uDFFE\u200D♂️", + [":man_bowing::skin-tone-5:"] = "\uD83D\uDE47\uD83C\uDFFF\u200D♂️", + [":man_bowing_dark_skin_tone:"] = "\uD83D\uDE47\uD83C\uDFFF\u200D♂️", + [":man_bowing_light_skin_tone:"] = "\uD83D\uDE47\uD83C\uDFFB\u200D♂️", + [":man_bowing_medium_dark_skin_tone:"] = "\uD83D\uDE47\uD83C\uDFFE\u200D♂️", + [":man_bowing_medium_light_skin_tone:"] = "\uD83D\uDE47\uD83C\uDFFC\u200D♂️", + [":man_bowing_medium_skin_tone:"] = "\uD83D\uDE47\uD83C\uDFFD\u200D♂️", + [":man_bowing_tone1:"] = "\uD83D\uDE47\uD83C\uDFFB\u200D♂️", + [":man_bowing_tone2:"] = "\uD83D\uDE47\uD83C\uDFFC\u200D♂️", + [":man_bowing_tone3:"] = "\uD83D\uDE47\uD83C\uDFFD\u200D♂️", + [":man_bowing_tone4:"] = "\uD83D\uDE47\uD83C\uDFFE\u200D♂️", + [":man_bowing_tone5:"] = "\uD83D\uDE47\uD83C\uDFFF\u200D♂️", + [":man_cartwheeling:"] = "\uD83E\uDD38\u200D♂️", + [":man_cartwheeling::skin-tone-1:"] = "\uD83E\uDD38\uD83C\uDFFB\u200D♂️", + [":man_cartwheeling::skin-tone-2:"] = "\uD83E\uDD38\uD83C\uDFFC\u200D♂️", + [":man_cartwheeling::skin-tone-3:"] = "\uD83E\uDD38\uD83C\uDFFD\u200D♂️", + [":man_cartwheeling::skin-tone-4:"] = "\uD83E\uDD38\uD83C\uDFFE\u200D♂️", + [":man_cartwheeling::skin-tone-5:"] = "\uD83E\uDD38\uD83C\uDFFF\u200D♂️", + [":man_cartwheeling_dark_skin_tone:"] = "\uD83E\uDD38\uD83C\uDFFF\u200D♂️", + [":man_cartwheeling_light_skin_tone:"] = "\uD83E\uDD38\uD83C\uDFFB\u200D♂️", + [":man_cartwheeling_medium_dark_skin_tone:"] = "\uD83E\uDD38\uD83C\uDFFE\u200D♂️", + [":man_cartwheeling_medium_light_skin_tone:"] = "\uD83E\uDD38\uD83C\uDFFC\u200D♂️", + [":man_cartwheeling_medium_skin_tone:"] = "\uD83E\uDD38\uD83C\uDFFD\u200D♂️", + [":man_cartwheeling_tone1:"] = "\uD83E\uDD38\uD83C\uDFFB\u200D♂️", + [":man_cartwheeling_tone2:"] = "\uD83E\uDD38\uD83C\uDFFC\u200D♂️", + [":man_cartwheeling_tone3:"] = "\uD83E\uDD38\uD83C\uDFFD\u200D♂️", + [":man_cartwheeling_tone4:"] = "\uD83E\uDD38\uD83C\uDFFE\u200D♂️", + [":man_cartwheeling_tone5:"] = "\uD83E\uDD38\uD83C\uDFFF\u200D♂️", + [":man_climbing:"] = "\uD83E\uDDD7\u200D♂️", + [":man_climbing::skin-tone-1:"] = "\uD83E\uDDD7\uD83C\uDFFB\u200D♂️", + [":man_climbing::skin-tone-2:"] = "\uD83E\uDDD7\uD83C\uDFFC\u200D♂️", + [":man_climbing::skin-tone-3:"] = "\uD83E\uDDD7\uD83C\uDFFD\u200D♂️", + [":man_climbing::skin-tone-4:"] = "\uD83E\uDDD7\uD83C\uDFFE\u200D♂️", + [":man_climbing::skin-tone-5:"] = "\uD83E\uDDD7\uD83C\uDFFF\u200D♂️", + [":man_climbing_dark_skin_tone:"] = "\uD83E\uDDD7\uD83C\uDFFF\u200D♂️", + [":man_climbing_light_skin_tone:"] = "\uD83E\uDDD7\uD83C\uDFFB\u200D♂️", + [":man_climbing_medium_dark_skin_tone:"] = "\uD83E\uDDD7\uD83C\uDFFE\u200D♂️", + [":man_climbing_medium_light_skin_tone:"] = "\uD83E\uDDD7\uD83C\uDFFC\u200D♂️", + [":man_climbing_medium_skin_tone:"] = "\uD83E\uDDD7\uD83C\uDFFD\u200D♂️", + [":man_climbing_tone1:"] = "\uD83E\uDDD7\uD83C\uDFFB\u200D♂️", + [":man_climbing_tone2:"] = "\uD83E\uDDD7\uD83C\uDFFC\u200D♂️", + [":man_climbing_tone3:"] = "\uD83E\uDDD7\uD83C\uDFFD\u200D♂️", + [":man_climbing_tone4:"] = "\uD83E\uDDD7\uD83C\uDFFE\u200D♂️", + [":man_climbing_tone5:"] = "\uD83E\uDDD7\uD83C\uDFFF\u200D♂️", + [":man_construction_worker:"] = "\uD83D\uDC77\u200D♂️", + [":man_construction_worker::skin-tone-1:"] = "\uD83D\uDC77\uD83C\uDFFB\u200D♂️", + [":man_construction_worker::skin-tone-2:"] = "\uD83D\uDC77\uD83C\uDFFC\u200D♂️", + [":man_construction_worker::skin-tone-3:"] = "\uD83D\uDC77\uD83C\uDFFD\u200D♂️", + [":man_construction_worker::skin-tone-4:"] = "\uD83D\uDC77\uD83C\uDFFE\u200D♂️", + [":man_construction_worker::skin-tone-5:"] = "\uD83D\uDC77\uD83C\uDFFF\u200D♂️", + [":man_construction_worker_dark_skin_tone:"] = "\uD83D\uDC77\uD83C\uDFFF\u200D♂️", + [":man_construction_worker_light_skin_tone:"] = "\uD83D\uDC77\uD83C\uDFFB\u200D♂️", + [":man_construction_worker_medium_dark_skin_tone:"] = "\uD83D\uDC77\uD83C\uDFFE\u200D♂️", + [":man_construction_worker_medium_light_skin_tone:"] = "\uD83D\uDC77\uD83C\uDFFC\u200D♂️", + [":man_construction_worker_medium_skin_tone:"] = "\uD83D\uDC77\uD83C\uDFFD\u200D♂️", + [":man_construction_worker_tone1:"] = "\uD83D\uDC77\uD83C\uDFFB\u200D♂️", + [":man_construction_worker_tone2:"] = "\uD83D\uDC77\uD83C\uDFFC\u200D♂️", + [":man_construction_worker_tone3:"] = "\uD83D\uDC77\uD83C\uDFFD\u200D♂️", + [":man_construction_worker_tone4:"] = "\uD83D\uDC77\uD83C\uDFFE\u200D♂️", + [":man_construction_worker_tone5:"] = "\uD83D\uDC77\uD83C\uDFFF\u200D♂️", + [":man_cook:"] = "\uD83D\uDC68\u200D\uD83C\uDF73", + [":man_cook::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDF73", + [":man_cook::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDF73", + [":man_cook::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDF73", + [":man_cook::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDF73", + [":man_cook::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDF73", + [":man_cook_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDF73", + [":man_cook_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDF73", + [":man_cook_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDF73", + [":man_cook_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDF73", + [":man_cook_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDF73", + [":man_cook_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDF73", + [":man_cook_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDF73", + [":man_cook_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDF73", + [":man_cook_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDF73", + [":man_cook_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDF73", + [":man_curly_haired:"] = "\uD83D\uDC68\u200D\uD83E\uDDB1", + [":man_curly_haired::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDB1", + [":man_curly_haired::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDB1", + [":man_curly_haired::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDB1", + [":man_curly_haired::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDB1", + [":man_curly_haired::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDB1", + [":man_curly_haired_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDB1", + [":man_curly_haired_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDB1", + [":man_curly_haired_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDB1", + [":man_curly_haired_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDB1", + [":man_curly_haired_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDB1", + [":man_curly_haired_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDB1", + [":man_curly_haired_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDB1", + [":man_curly_haired_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDB1", + [":man_curly_haired_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDB1", + [":man_curly_haired_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDB1", + [":man_dancing:"] = "\uD83D\uDD7A", + [":man_dancing::skin-tone-1:"] = "\uD83D\uDD7A\uD83C\uDFFB", + [":man_dancing::skin-tone-2:"] = "\uD83D\uDD7A\uD83C\uDFFC", + [":man_dancing::skin-tone-3:"] = "\uD83D\uDD7A\uD83C\uDFFD", + [":man_dancing::skin-tone-4:"] = "\uD83D\uDD7A\uD83C\uDFFE", + [":man_dancing::skin-tone-5:"] = "\uD83D\uDD7A\uD83C\uDFFF", + [":man_dancing_tone1:"] = "\uD83D\uDD7A\uD83C\uDFFB", + [":man_dancing_tone2:"] = "\uD83D\uDD7A\uD83C\uDFFC", + [":man_dancing_tone3:"] = "\uD83D\uDD7A\uD83C\uDFFD", + [":man_dancing_tone4:"] = "\uD83D\uDD7A\uD83C\uDFFE", + [":man_dancing_tone5:"] = "\uD83D\uDD7A\uD83C\uDFFF", + [":man_detective:"] = "\uD83D\uDD75️\u200D♂️", + [":man_detective::skin-tone-1:"] = "\uD83D\uDD75\uD83C\uDFFB\u200D♂️", + [":man_detective::skin-tone-2:"] = "\uD83D\uDD75\uD83C\uDFFC\u200D♂️", + [":man_detective::skin-tone-3:"] = "\uD83D\uDD75\uD83C\uDFFD\u200D♂️", + [":man_detective::skin-tone-4:"] = "\uD83D\uDD75\uD83C\uDFFE\u200D♂️", + [":man_detective::skin-tone-5:"] = "\uD83D\uDD75\uD83C\uDFFF\u200D♂️", + [":man_detective_dark_skin_tone:"] = "\uD83D\uDD75\uD83C\uDFFF\u200D♂️", + [":man_detective_light_skin_tone:"] = "\uD83D\uDD75\uD83C\uDFFB\u200D♂️", + [":man_detective_medium_dark_skin_tone:"] = "\uD83D\uDD75\uD83C\uDFFE\u200D♂️", + [":man_detective_medium_light_skin_tone:"] = "\uD83D\uDD75\uD83C\uDFFC\u200D♂️", + [":man_detective_medium_skin_tone:"] = "\uD83D\uDD75\uD83C\uDFFD\u200D♂️", + [":man_detective_tone1:"] = "\uD83D\uDD75\uD83C\uDFFB\u200D♂️", + [":man_detective_tone2:"] = "\uD83D\uDD75\uD83C\uDFFC\u200D♂️", + [":man_detective_tone3:"] = "\uD83D\uDD75\uD83C\uDFFD\u200D♂️", + [":man_detective_tone4:"] = "\uD83D\uDD75\uD83C\uDFFE\u200D♂️", + [":man_detective_tone5:"] = "\uD83D\uDD75\uD83C\uDFFF\u200D♂️", + [":man_elf:"] = "\uD83E\uDDDD\u200D♂️", + [":man_elf::skin-tone-1:"] = "\uD83E\uDDDD\uD83C\uDFFB\u200D♂️", + [":man_elf::skin-tone-2:"] = "\uD83E\uDDDD\uD83C\uDFFC\u200D♂️", + [":man_elf::skin-tone-3:"] = "\uD83E\uDDDD\uD83C\uDFFD\u200D♂️", + [":man_elf::skin-tone-4:"] = "\uD83E\uDDDD\uD83C\uDFFE\u200D♂️", + [":man_elf::skin-tone-5:"] = "\uD83E\uDDDD\uD83C\uDFFF\u200D♂️", + [":man_elf_dark_skin_tone:"] = "\uD83E\uDDDD\uD83C\uDFFF\u200D♂️", + [":man_elf_light_skin_tone:"] = "\uD83E\uDDDD\uD83C\uDFFB\u200D♂️", + [":man_elf_medium_dark_skin_tone:"] = "\uD83E\uDDDD\uD83C\uDFFE\u200D♂️", + [":man_elf_medium_light_skin_tone:"] = "\uD83E\uDDDD\uD83C\uDFFC\u200D♂️", + [":man_elf_medium_skin_tone:"] = "\uD83E\uDDDD\uD83C\uDFFD\u200D♂️", + [":man_elf_tone1:"] = "\uD83E\uDDDD\uD83C\uDFFB\u200D♂️", + [":man_elf_tone2:"] = "\uD83E\uDDDD\uD83C\uDFFC\u200D♂️", + [":man_elf_tone3:"] = "\uD83E\uDDDD\uD83C\uDFFD\u200D♂️", + [":man_elf_tone4:"] = "\uD83E\uDDDD\uD83C\uDFFE\u200D♂️", + [":man_elf_tone5:"] = "\uD83E\uDDDD\uD83C\uDFFF\u200D♂️", + [":man_facepalming:"] = "\uD83E\uDD26\u200D♂️", + [":man_facepalming::skin-tone-1:"] = "\uD83E\uDD26\uD83C\uDFFB\u200D♂️", + [":man_facepalming::skin-tone-2:"] = "\uD83E\uDD26\uD83C\uDFFC\u200D♂️", + [":man_facepalming::skin-tone-3:"] = "\uD83E\uDD26\uD83C\uDFFD\u200D♂️", + [":man_facepalming::skin-tone-4:"] = "\uD83E\uDD26\uD83C\uDFFE\u200D♂️", + [":man_facepalming::skin-tone-5:"] = "\uD83E\uDD26\uD83C\uDFFF\u200D♂️", + [":man_facepalming_dark_skin_tone:"] = "\uD83E\uDD26\uD83C\uDFFF\u200D♂️", + [":man_facepalming_light_skin_tone:"] = "\uD83E\uDD26\uD83C\uDFFB\u200D♂️", + [":man_facepalming_medium_dark_skin_tone:"] = "\uD83E\uDD26\uD83C\uDFFE\u200D♂️", + [":man_facepalming_medium_light_skin_tone:"] = "\uD83E\uDD26\uD83C\uDFFC\u200D♂️", + [":man_facepalming_medium_skin_tone:"] = "\uD83E\uDD26\uD83C\uDFFD\u200D♂️", + [":man_facepalming_tone1:"] = "\uD83E\uDD26\uD83C\uDFFB\u200D♂️", + [":man_facepalming_tone2:"] = "\uD83E\uDD26\uD83C\uDFFC\u200D♂️", + [":man_facepalming_tone3:"] = "\uD83E\uDD26\uD83C\uDFFD\u200D♂️", + [":man_facepalming_tone4:"] = "\uD83E\uDD26\uD83C\uDFFE\u200D♂️", + [":man_facepalming_tone5:"] = "\uD83E\uDD26\uD83C\uDFFF\u200D♂️", + [":man_factory_worker:"] = "\uD83D\uDC68\u200D\uD83C\uDFED", + [":man_factory_worker::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDFED", + [":man_factory_worker::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDFED", + [":man_factory_worker::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDFED", + [":man_factory_worker::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDFED", + [":man_factory_worker::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDFED", + [":man_factory_worker_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDFED", + [":man_factory_worker_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDFED", + [":man_factory_worker_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDFED", + [":man_factory_worker_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDFED", + [":man_factory_worker_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDFED", + [":man_factory_worker_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDFED", + [":man_factory_worker_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDFED", + [":man_factory_worker_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDFED", + [":man_factory_worker_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDFED", + [":man_factory_worker_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDFED", + [":man_fairy:"] = "\uD83E\uDDDA\u200D♂️", + [":man_fairy::skin-tone-1:"] = "\uD83E\uDDDA\uD83C\uDFFB\u200D♂️", + [":man_fairy::skin-tone-2:"] = "\uD83E\uDDDA\uD83C\uDFFC\u200D♂️", + [":man_fairy::skin-tone-3:"] = "\uD83E\uDDDA\uD83C\uDFFD\u200D♂️", + [":man_fairy::skin-tone-4:"] = "\uD83E\uDDDA\uD83C\uDFFE\u200D♂️", + [":man_fairy::skin-tone-5:"] = "\uD83E\uDDDA\uD83C\uDFFF\u200D♂️", + [":man_fairy_dark_skin_tone:"] = "\uD83E\uDDDA\uD83C\uDFFF\u200D♂️", + [":man_fairy_light_skin_tone:"] = "\uD83E\uDDDA\uD83C\uDFFB\u200D♂️", + [":man_fairy_medium_dark_skin_tone:"] = "\uD83E\uDDDA\uD83C\uDFFE\u200D♂️", + [":man_fairy_medium_light_skin_tone:"] = "\uD83E\uDDDA\uD83C\uDFFC\u200D♂️", + [":man_fairy_medium_skin_tone:"] = "\uD83E\uDDDA\uD83C\uDFFD\u200D♂️", + [":man_fairy_tone1:"] = "\uD83E\uDDDA\uD83C\uDFFB\u200D♂️", + [":man_fairy_tone2:"] = "\uD83E\uDDDA\uD83C\uDFFC\u200D♂️", + [":man_fairy_tone3:"] = "\uD83E\uDDDA\uD83C\uDFFD\u200D♂️", + [":man_fairy_tone4:"] = "\uD83E\uDDDA\uD83C\uDFFE\u200D♂️", + [":man_fairy_tone5:"] = "\uD83E\uDDDA\uD83C\uDFFF\u200D♂️", + [":man_farmer:"] = "\uD83D\uDC68\u200D\uD83C\uDF3E", + [":man_farmer::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDF3E", + [":man_farmer::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDF3E", + [":man_farmer::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDF3E", + [":man_farmer::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDF3E", + [":man_farmer::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDF3E", + [":man_farmer_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDF3E", + [":man_farmer_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDF3E", + [":man_farmer_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDF3E", + [":man_farmer_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDF3E", + [":man_farmer_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDF3E", + [":man_farmer_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDF3E", + [":man_farmer_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDF3E", + [":man_farmer_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDF3E", + [":man_farmer_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDF3E", + [":man_farmer_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDF3E", + [":man_firefighter:"] = "\uD83D\uDC68\u200D\uD83D\uDE92", + [":man_firefighter::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDE92", + [":man_firefighter::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDE92", + [":man_firefighter::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDE92", + [":man_firefighter::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDE92", + [":man_firefighter::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDE92", + [":man_firefighter_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDE92", + [":man_firefighter_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDE92", + [":man_firefighter_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDE92", + [":man_firefighter_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDE92", + [":man_firefighter_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDE92", + [":man_firefighter_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDE92", + [":man_firefighter_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDE92", + [":man_firefighter_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDE92", + [":man_firefighter_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDE92", + [":man_firefighter_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDE92", + [":man_frowning:"] = "\uD83D\uDE4D\u200D♂️", + [":man_frowning::skin-tone-1:"] = "\uD83D\uDE4D\uD83C\uDFFB\u200D♂️", + [":man_frowning::skin-tone-2:"] = "\uD83D\uDE4D\uD83C\uDFFC\u200D♂️", + [":man_frowning::skin-tone-3:"] = "\uD83D\uDE4D\uD83C\uDFFD\u200D♂️", + [":man_frowning::skin-tone-4:"] = "\uD83D\uDE4D\uD83C\uDFFE\u200D♂️", + [":man_frowning::skin-tone-5:"] = "\uD83D\uDE4D\uD83C\uDFFF\u200D♂️", + [":man_frowning_dark_skin_tone:"] = "\uD83D\uDE4D\uD83C\uDFFF\u200D♂️", + [":man_frowning_light_skin_tone:"] = "\uD83D\uDE4D\uD83C\uDFFB\u200D♂️", + [":man_frowning_medium_dark_skin_tone:"] = "\uD83D\uDE4D\uD83C\uDFFE\u200D♂️", + [":man_frowning_medium_light_skin_tone:"] = "\uD83D\uDE4D\uD83C\uDFFC\u200D♂️", + [":man_frowning_medium_skin_tone:"] = "\uD83D\uDE4D\uD83C\uDFFD\u200D♂️", + [":man_frowning_tone1:"] = "\uD83D\uDE4D\uD83C\uDFFB\u200D♂️", + [":man_frowning_tone2:"] = "\uD83D\uDE4D\uD83C\uDFFC\u200D♂️", + [":man_frowning_tone3:"] = "\uD83D\uDE4D\uD83C\uDFFD\u200D♂️", + [":man_frowning_tone4:"] = "\uD83D\uDE4D\uD83C\uDFFE\u200D♂️", + [":man_frowning_tone5:"] = "\uD83D\uDE4D\uD83C\uDFFF\u200D♂️", + [":man_genie:"] = "\uD83E\uDDDE\u200D♂️", + [":man_gesturing_no:"] = "\uD83D\uDE45\u200D♂️", + [":man_gesturing_no::skin-tone-1:"] = "\uD83D\uDE45\uD83C\uDFFB\u200D♂️", + [":man_gesturing_no::skin-tone-2:"] = "\uD83D\uDE45\uD83C\uDFFC\u200D♂️", + [":man_gesturing_no::skin-tone-3:"] = "\uD83D\uDE45\uD83C\uDFFD\u200D♂️", + [":man_gesturing_no::skin-tone-4:"] = "\uD83D\uDE45\uD83C\uDFFE\u200D♂️", + [":man_gesturing_no::skin-tone-5:"] = "\uD83D\uDE45\uD83C\uDFFF\u200D♂️", + [":man_gesturing_no_dark_skin_tone:"] = "\uD83D\uDE45\uD83C\uDFFF\u200D♂️", + [":man_gesturing_no_light_skin_tone:"] = "\uD83D\uDE45\uD83C\uDFFB\u200D♂️", + [":man_gesturing_no_medium_dark_skin_tone:"] = "\uD83D\uDE45\uD83C\uDFFE\u200D♂️", + [":man_gesturing_no_medium_light_skin_tone:"] = "\uD83D\uDE45\uD83C\uDFFC\u200D♂️", + [":man_gesturing_no_medium_skin_tone:"] = "\uD83D\uDE45\uD83C\uDFFD\u200D♂️", + [":man_gesturing_no_tone1:"] = "\uD83D\uDE45\uD83C\uDFFB\u200D♂️", + [":man_gesturing_no_tone2:"] = "\uD83D\uDE45\uD83C\uDFFC\u200D♂️", + [":man_gesturing_no_tone3:"] = "\uD83D\uDE45\uD83C\uDFFD\u200D♂️", + [":man_gesturing_no_tone4:"] = "\uD83D\uDE45\uD83C\uDFFE\u200D♂️", + [":man_gesturing_no_tone5:"] = "\uD83D\uDE45\uD83C\uDFFF\u200D♂️", + [":man_gesturing_ok:"] = "\uD83D\uDE46\u200D♂️", + [":man_gesturing_ok::skin-tone-1:"] = "\uD83D\uDE46\uD83C\uDFFB\u200D♂️", + [":man_gesturing_ok::skin-tone-2:"] = "\uD83D\uDE46\uD83C\uDFFC\u200D♂️", + [":man_gesturing_ok::skin-tone-3:"] = "\uD83D\uDE46\uD83C\uDFFD\u200D♂️", + [":man_gesturing_ok::skin-tone-4:"] = "\uD83D\uDE46\uD83C\uDFFE\u200D♂️", + [":man_gesturing_ok::skin-tone-5:"] = "\uD83D\uDE46\uD83C\uDFFF\u200D♂️", + [":man_gesturing_ok_dark_skin_tone:"] = "\uD83D\uDE46\uD83C\uDFFF\u200D♂️", + [":man_gesturing_ok_light_skin_tone:"] = "\uD83D\uDE46\uD83C\uDFFB\u200D♂️", + [":man_gesturing_ok_medium_dark_skin_tone:"] = "\uD83D\uDE46\uD83C\uDFFE\u200D♂️", + [":man_gesturing_ok_medium_light_skin_tone:"] = "\uD83D\uDE46\uD83C\uDFFC\u200D♂️", + [":man_gesturing_ok_medium_skin_tone:"] = "\uD83D\uDE46\uD83C\uDFFD\u200D♂️", + [":man_gesturing_ok_tone1:"] = "\uD83D\uDE46\uD83C\uDFFB\u200D♂️", + [":man_gesturing_ok_tone2:"] = "\uD83D\uDE46\uD83C\uDFFC\u200D♂️", + [":man_gesturing_ok_tone3:"] = "\uD83D\uDE46\uD83C\uDFFD\u200D♂️", + [":man_gesturing_ok_tone4:"] = "\uD83D\uDE46\uD83C\uDFFE\u200D♂️", + [":man_gesturing_ok_tone5:"] = "\uD83D\uDE46\uD83C\uDFFF\u200D♂️", + [":man_getting_face_massage:"] = "\uD83D\uDC86\u200D♂️", + [":man_getting_face_massage::skin-tone-1:"] = "\uD83D\uDC86\uD83C\uDFFB\u200D♂️", + [":man_getting_face_massage::skin-tone-2:"] = "\uD83D\uDC86\uD83C\uDFFC\u200D♂️", + [":man_getting_face_massage::skin-tone-3:"] = "\uD83D\uDC86\uD83C\uDFFD\u200D♂️", + [":man_getting_face_massage::skin-tone-4:"] = "\uD83D\uDC86\uD83C\uDFFE\u200D♂️", + [":man_getting_face_massage::skin-tone-5:"] = "\uD83D\uDC86\uD83C\uDFFF\u200D♂️", + [":man_getting_face_massage_dark_skin_tone:"] = "\uD83D\uDC86\uD83C\uDFFF\u200D♂️", + [":man_getting_face_massage_light_skin_tone:"] = "\uD83D\uDC86\uD83C\uDFFB\u200D♂️", + [":man_getting_face_massage_medium_dark_skin_tone:"] = "\uD83D\uDC86\uD83C\uDFFE\u200D♂️", + [":man_getting_face_massage_medium_light_skin_tone:"] = "\uD83D\uDC86\uD83C\uDFFC\u200D♂️", + [":man_getting_face_massage_medium_skin_tone:"] = "\uD83D\uDC86\uD83C\uDFFD\u200D♂️", + [":man_getting_face_massage_tone1:"] = "\uD83D\uDC86\uD83C\uDFFB\u200D♂️", + [":man_getting_face_massage_tone2:"] = "\uD83D\uDC86\uD83C\uDFFC\u200D♂️", + [":man_getting_face_massage_tone3:"] = "\uD83D\uDC86\uD83C\uDFFD\u200D♂️", + [":man_getting_face_massage_tone4:"] = "\uD83D\uDC86\uD83C\uDFFE\u200D♂️", + [":man_getting_face_massage_tone5:"] = "\uD83D\uDC86\uD83C\uDFFF\u200D♂️", + [":man_getting_haircut:"] = "\uD83D\uDC87\u200D♂️", + [":man_getting_haircut::skin-tone-1:"] = "\uD83D\uDC87\uD83C\uDFFB\u200D♂️", + [":man_getting_haircut::skin-tone-2:"] = "\uD83D\uDC87\uD83C\uDFFC\u200D♂️", + [":man_getting_haircut::skin-tone-3:"] = "\uD83D\uDC87\uD83C\uDFFD\u200D♂️", + [":man_getting_haircut::skin-tone-4:"] = "\uD83D\uDC87\uD83C\uDFFE\u200D♂️", + [":man_getting_haircut::skin-tone-5:"] = "\uD83D\uDC87\uD83C\uDFFF\u200D♂️", + [":man_getting_haircut_dark_skin_tone:"] = "\uD83D\uDC87\uD83C\uDFFF\u200D♂️", + [":man_getting_haircut_light_skin_tone:"] = "\uD83D\uDC87\uD83C\uDFFB\u200D♂️", + [":man_getting_haircut_medium_dark_skin_tone:"] = "\uD83D\uDC87\uD83C\uDFFE\u200D♂️", + [":man_getting_haircut_medium_light_skin_tone:"] = "\uD83D\uDC87\uD83C\uDFFC\u200D♂️", + [":man_getting_haircut_medium_skin_tone:"] = "\uD83D\uDC87\uD83C\uDFFD\u200D♂️", + [":man_getting_haircut_tone1:"] = "\uD83D\uDC87\uD83C\uDFFB\u200D♂️", + [":man_getting_haircut_tone2:"] = "\uD83D\uDC87\uD83C\uDFFC\u200D♂️", + [":man_getting_haircut_tone3:"] = "\uD83D\uDC87\uD83C\uDFFD\u200D♂️", + [":man_getting_haircut_tone4:"] = "\uD83D\uDC87\uD83C\uDFFE\u200D♂️", + [":man_getting_haircut_tone5:"] = "\uD83D\uDC87\uD83C\uDFFF\u200D♂️", + [":man_golfing:"] = "\uD83C\uDFCC️\u200D♂️", + [":man_golfing::skin-tone-1:"] = "\uD83C\uDFCC\uD83C\uDFFB\u200D♂️", + [":man_golfing::skin-tone-2:"] = "\uD83C\uDFCC\uD83C\uDFFC\u200D♂️", + [":man_golfing::skin-tone-3:"] = "\uD83C\uDFCC\uD83C\uDFFD\u200D♂️", + [":man_golfing::skin-tone-4:"] = "\uD83C\uDFCC\uD83C\uDFFE\u200D♂️", + [":man_golfing::skin-tone-5:"] = "\uD83C\uDFCC\uD83C\uDFFF\u200D♂️", + [":man_golfing_dark_skin_tone:"] = "\uD83C\uDFCC\uD83C\uDFFF\u200D♂️", + [":man_golfing_light_skin_tone:"] = "\uD83C\uDFCC\uD83C\uDFFB\u200D♂️", + [":man_golfing_medium_dark_skin_tone:"] = "\uD83C\uDFCC\uD83C\uDFFE\u200D♂️", + [":man_golfing_medium_light_skin_tone:"] = "\uD83C\uDFCC\uD83C\uDFFC\u200D♂️", + [":man_golfing_medium_skin_tone:"] = "\uD83C\uDFCC\uD83C\uDFFD\u200D♂️", + [":man_golfing_tone1:"] = "\uD83C\uDFCC\uD83C\uDFFB\u200D♂️", + [":man_golfing_tone2:"] = "\uD83C\uDFCC\uD83C\uDFFC\u200D♂️", + [":man_golfing_tone3:"] = "\uD83C\uDFCC\uD83C\uDFFD\u200D♂️", + [":man_golfing_tone4:"] = "\uD83C\uDFCC\uD83C\uDFFE\u200D♂️", + [":man_golfing_tone5:"] = "\uD83C\uDFCC\uD83C\uDFFF\u200D♂️", + [":man_guard:"] = "\uD83D\uDC82\u200D♂️", + [":man_guard::skin-tone-1:"] = "\uD83D\uDC82\uD83C\uDFFB\u200D♂️", + [":man_guard::skin-tone-2:"] = "\uD83D\uDC82\uD83C\uDFFC\u200D♂️", + [":man_guard::skin-tone-3:"] = "\uD83D\uDC82\uD83C\uDFFD\u200D♂️", + [":man_guard::skin-tone-4:"] = "\uD83D\uDC82\uD83C\uDFFE\u200D♂️", + [":man_guard::skin-tone-5:"] = "\uD83D\uDC82\uD83C\uDFFF\u200D♂️", + [":man_guard_dark_skin_tone:"] = "\uD83D\uDC82\uD83C\uDFFF\u200D♂️", + [":man_guard_light_skin_tone:"] = "\uD83D\uDC82\uD83C\uDFFB\u200D♂️", + [":man_guard_medium_dark_skin_tone:"] = "\uD83D\uDC82\uD83C\uDFFE\u200D♂️", + [":man_guard_medium_light_skin_tone:"] = "\uD83D\uDC82\uD83C\uDFFC\u200D♂️", + [":man_guard_medium_skin_tone:"] = "\uD83D\uDC82\uD83C\uDFFD\u200D♂️", + [":man_guard_tone1:"] = "\uD83D\uDC82\uD83C\uDFFB\u200D♂️", + [":man_guard_tone2:"] = "\uD83D\uDC82\uD83C\uDFFC\u200D♂️", + [":man_guard_tone3:"] = "\uD83D\uDC82\uD83C\uDFFD\u200D♂️", + [":man_guard_tone4:"] = "\uD83D\uDC82\uD83C\uDFFE\u200D♂️", + [":man_guard_tone5:"] = "\uD83D\uDC82\uD83C\uDFFF\u200D♂️", + [":man_health_worker:"] = "\uD83D\uDC68\u200D⚕️", + [":man_health_worker::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D⚕️", + [":man_health_worker::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D⚕️", + [":man_health_worker::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D⚕️", + [":man_health_worker::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D⚕️", + [":man_health_worker::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D⚕️", + [":man_health_worker_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D⚕️", + [":man_health_worker_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D⚕️", + [":man_health_worker_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D⚕️", + [":man_health_worker_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D⚕️", + [":man_health_worker_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D⚕️", + [":man_health_worker_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D⚕️", + [":man_health_worker_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D⚕️", + [":man_health_worker_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D⚕️", + [":man_health_worker_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D⚕️", + [":man_health_worker_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D⚕️", + [":man_in_business_suit_levitating:"] = "\uD83D\uDD74️", + [":man_in_business_suit_levitating::skin-tone-1:"] = "\uD83D\uDD74\uD83C\uDFFB", + [":man_in_business_suit_levitating::skin-tone-2:"] = "\uD83D\uDD74\uD83C\uDFFC", + [":man_in_business_suit_levitating::skin-tone-3:"] = "\uD83D\uDD74\uD83C\uDFFD", + [":man_in_business_suit_levitating::skin-tone-4:"] = "\uD83D\uDD74\uD83C\uDFFE", + [":man_in_business_suit_levitating::skin-tone-5:"] = "\uD83D\uDD74\uD83C\uDFFF", + [":man_in_business_suit_levitating_dark_skin_tone:"] = "\uD83D\uDD74\uD83C\uDFFF", + [":man_in_business_suit_levitating_light_skin_tone:"] = "\uD83D\uDD74\uD83C\uDFFB", + [":man_in_business_suit_levitating_medium_dark_skin_tone:"] = "\uD83D\uDD74\uD83C\uDFFE", + [":man_in_business_suit_levitating_medium_light_skin_tone:"] = "\uD83D\uDD74\uD83C\uDFFC", + [":man_in_business_suit_levitating_medium_skin_tone:"] = "\uD83D\uDD74\uD83C\uDFFD", + [":man_in_business_suit_levitating_tone1:"] = "\uD83D\uDD74\uD83C\uDFFB", + [":man_in_business_suit_levitating_tone2:"] = "\uD83D\uDD74\uD83C\uDFFC", + [":man_in_business_suit_levitating_tone3:"] = "\uD83D\uDD74\uD83C\uDFFD", + [":man_in_business_suit_levitating_tone4:"] = "\uD83D\uDD74\uD83C\uDFFE", + [":man_in_business_suit_levitating_tone5:"] = "\uD83D\uDD74\uD83C\uDFFF", + [":man_in_lotus_position:"] = "\uD83E\uDDD8\u200D♂️", + [":man_in_lotus_position::skin-tone-1:"] = "\uD83E\uDDD8\uD83C\uDFFB\u200D♂️", + [":man_in_lotus_position::skin-tone-2:"] = "\uD83E\uDDD8\uD83C\uDFFC\u200D♂️", + [":man_in_lotus_position::skin-tone-3:"] = "\uD83E\uDDD8\uD83C\uDFFD\u200D♂️", + [":man_in_lotus_position::skin-tone-4:"] = "\uD83E\uDDD8\uD83C\uDFFE\u200D♂️", + [":man_in_lotus_position::skin-tone-5:"] = "\uD83E\uDDD8\uD83C\uDFFF\u200D♂️", + [":man_in_lotus_position_dark_skin_tone:"] = "\uD83E\uDDD8\uD83C\uDFFF\u200D♂️", + [":man_in_lotus_position_light_skin_tone:"] = "\uD83E\uDDD8\uD83C\uDFFB\u200D♂️", + [":man_in_lotus_position_medium_dark_skin_tone:"] = "\uD83E\uDDD8\uD83C\uDFFE\u200D♂️", + [":man_in_lotus_position_medium_light_skin_tone:"] = "\uD83E\uDDD8\uD83C\uDFFC\u200D♂️", + [":man_in_lotus_position_medium_skin_tone:"] = "\uD83E\uDDD8\uD83C\uDFFD\u200D♂️", + [":man_in_lotus_position_tone1:"] = "\uD83E\uDDD8\uD83C\uDFFB\u200D♂️", + [":man_in_lotus_position_tone2:"] = "\uD83E\uDDD8\uD83C\uDFFC\u200D♂️", + [":man_in_lotus_position_tone3:"] = "\uD83E\uDDD8\uD83C\uDFFD\u200D♂️", + [":man_in_lotus_position_tone4:"] = "\uD83E\uDDD8\uD83C\uDFFE\u200D♂️", + [":man_in_lotus_position_tone5:"] = "\uD83E\uDDD8\uD83C\uDFFF\u200D♂️", + [":man_in_manual_wheelchair:"] = "\uD83D\uDC68\u200D\uD83E\uDDBD", + [":man_in_manual_wheelchair::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDBD", + [":man_in_manual_wheelchair::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDBD", + [":man_in_manual_wheelchair::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDBD", + [":man_in_manual_wheelchair::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDBD", + [":man_in_manual_wheelchair::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDBD", + [":man_in_manual_wheelchair_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDBD", + [":man_in_manual_wheelchair_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDBD", + [":man_in_manual_wheelchair_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDBD", + [":man_in_manual_wheelchair_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDBD", + [":man_in_manual_wheelchair_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDBD", + [":man_in_manual_wheelchair_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDBD", + [":man_in_manual_wheelchair_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDBD", + [":man_in_manual_wheelchair_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDBD", + [":man_in_manual_wheelchair_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDBD", + [":man_in_manual_wheelchair_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDBD", + [":man_in_motorized_wheelchair:"] = "\uD83D\uDC68\u200D\uD83E\uDDBC", + [":man_in_motorized_wheelchair::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDBC", + [":man_in_motorized_wheelchair::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDBC", + [":man_in_motorized_wheelchair::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDBC", + [":man_in_motorized_wheelchair::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDBC", + [":man_in_motorized_wheelchair::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDBC", + [":man_in_motorized_wheelchair_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDBC", + [":man_in_motorized_wheelchair_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDBC", + [":man_in_motorized_wheelchair_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDBC", + [":man_in_motorized_wheelchair_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDBC", + [":man_in_motorized_wheelchair_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDBC", + [":man_in_motorized_wheelchair_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDBC", + [":man_in_motorized_wheelchair_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDBC", + [":man_in_motorized_wheelchair_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDBC", + [":man_in_motorized_wheelchair_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDBC", + [":man_in_motorized_wheelchair_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDBC", + [":man_in_steamy_room:"] = "\uD83E\uDDD6\u200D♂️", + [":man_in_steamy_room::skin-tone-1:"] = "\uD83E\uDDD6\uD83C\uDFFB\u200D♂️", + [":man_in_steamy_room::skin-tone-2:"] = "\uD83E\uDDD6\uD83C\uDFFC\u200D♂️", + [":man_in_steamy_room::skin-tone-3:"] = "\uD83E\uDDD6\uD83C\uDFFD\u200D♂️", + [":man_in_steamy_room::skin-tone-4:"] = "\uD83E\uDDD6\uD83C\uDFFE\u200D♂️", + [":man_in_steamy_room::skin-tone-5:"] = "\uD83E\uDDD6\uD83C\uDFFF\u200D♂️", + [":man_in_steamy_room_dark_skin_tone:"] = "\uD83E\uDDD6\uD83C\uDFFF\u200D♂️", + [":man_in_steamy_room_light_skin_tone:"] = "\uD83E\uDDD6\uD83C\uDFFB\u200D♂️", + [":man_in_steamy_room_medium_dark_skin_tone:"] = "\uD83E\uDDD6\uD83C\uDFFE\u200D♂️", + [":man_in_steamy_room_medium_light_skin_tone:"] = "\uD83E\uDDD6\uD83C\uDFFC\u200D♂️", + [":man_in_steamy_room_medium_skin_tone:"] = "\uD83E\uDDD6\uD83C\uDFFD\u200D♂️", + [":man_in_steamy_room_tone1:"] = "\uD83E\uDDD6\uD83C\uDFFB\u200D♂️", + [":man_in_steamy_room_tone2:"] = "\uD83E\uDDD6\uD83C\uDFFC\u200D♂️", + [":man_in_steamy_room_tone3:"] = "\uD83E\uDDD6\uD83C\uDFFD\u200D♂️", + [":man_in_steamy_room_tone4:"] = "\uD83E\uDDD6\uD83C\uDFFE\u200D♂️", + [":man_in_steamy_room_tone5:"] = "\uD83E\uDDD6\uD83C\uDFFF\u200D♂️", + [":man_in_tuxedo:"] = "\uD83E\uDD35", + [":man_in_tuxedo::skin-tone-1:"] = "\uD83E\uDD35\uD83C\uDFFB", + [":man_in_tuxedo::skin-tone-2:"] = "\uD83E\uDD35\uD83C\uDFFC", + [":man_in_tuxedo::skin-tone-3:"] = "\uD83E\uDD35\uD83C\uDFFD", + [":man_in_tuxedo::skin-tone-4:"] = "\uD83E\uDD35\uD83C\uDFFE", + [":man_in_tuxedo::skin-tone-5:"] = "\uD83E\uDD35\uD83C\uDFFF", + [":man_in_tuxedo_tone1:"] = "\uD83E\uDD35\uD83C\uDFFB", + [":man_in_tuxedo_tone2:"] = "\uD83E\uDD35\uD83C\uDFFC", + [":man_in_tuxedo_tone3:"] = "\uD83E\uDD35\uD83C\uDFFD", + [":man_in_tuxedo_tone4:"] = "\uD83E\uDD35\uD83C\uDFFE", + [":man_in_tuxedo_tone5:"] = "\uD83E\uDD35\uD83C\uDFFF", + [":man_judge:"] = "\uD83D\uDC68\u200D⚖️", + [":man_judge::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D⚖️", + [":man_judge::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D⚖️", + [":man_judge::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D⚖️", + [":man_judge::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D⚖️", + [":man_judge::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D⚖️", + [":man_judge_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D⚖️", + [":man_judge_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D⚖️", + [":man_judge_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D⚖️", + [":man_judge_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D⚖️", + [":man_judge_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D⚖️", + [":man_judge_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D⚖️", + [":man_judge_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D⚖️", + [":man_judge_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D⚖️", + [":man_judge_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D⚖️", + [":man_judge_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D⚖️", + [":man_juggling:"] = "\uD83E\uDD39\u200D♂️", + [":man_juggling::skin-tone-1:"] = "\uD83E\uDD39\uD83C\uDFFB\u200D♂️", + [":man_juggling::skin-tone-2:"] = "\uD83E\uDD39\uD83C\uDFFC\u200D♂️", + [":man_juggling::skin-tone-3:"] = "\uD83E\uDD39\uD83C\uDFFD\u200D♂️", + [":man_juggling::skin-tone-4:"] = "\uD83E\uDD39\uD83C\uDFFE\u200D♂️", + [":man_juggling::skin-tone-5:"] = "\uD83E\uDD39\uD83C\uDFFF\u200D♂️", + [":man_juggling_dark_skin_tone:"] = "\uD83E\uDD39\uD83C\uDFFF\u200D♂️", + [":man_juggling_light_skin_tone:"] = "\uD83E\uDD39\uD83C\uDFFB\u200D♂️", + [":man_juggling_medium_dark_skin_tone:"] = "\uD83E\uDD39\uD83C\uDFFE\u200D♂️", + [":man_juggling_medium_light_skin_tone:"] = "\uD83E\uDD39\uD83C\uDFFC\u200D♂️", + [":man_juggling_medium_skin_tone:"] = "\uD83E\uDD39\uD83C\uDFFD\u200D♂️", + [":man_juggling_tone1:"] = "\uD83E\uDD39\uD83C\uDFFB\u200D♂️", + [":man_juggling_tone2:"] = "\uD83E\uDD39\uD83C\uDFFC\u200D♂️", + [":man_juggling_tone3:"] = "\uD83E\uDD39\uD83C\uDFFD\u200D♂️", + [":man_juggling_tone4:"] = "\uD83E\uDD39\uD83C\uDFFE\u200D♂️", + [":man_juggling_tone5:"] = "\uD83E\uDD39\uD83C\uDFFF\u200D♂️", + [":man_kneeling:"] = "\uD83E\uDDCE\u200D♂️", + [":man_kneeling::skin-tone-1:"] = "\uD83E\uDDCE\uD83C\uDFFB\u200D♂️", + [":man_kneeling::skin-tone-2:"] = "\uD83E\uDDCE\uD83C\uDFFC\u200D♂️", + [":man_kneeling::skin-tone-3:"] = "\uD83E\uDDCE\uD83C\uDFFD\u200D♂️", + [":man_kneeling::skin-tone-4:"] = "\uD83E\uDDCE\uD83C\uDFFE\u200D♂️", + [":man_kneeling::skin-tone-5:"] = "\uD83E\uDDCE\uD83C\uDFFF\u200D♂️", + [":man_kneeling_dark_skin_tone:"] = "\uD83E\uDDCE\uD83C\uDFFF\u200D♂️", + [":man_kneeling_light_skin_tone:"] = "\uD83E\uDDCE\uD83C\uDFFB\u200D♂️", + [":man_kneeling_medium_dark_skin_tone:"] = "\uD83E\uDDCE\uD83C\uDFFE\u200D♂️", + [":man_kneeling_medium_light_skin_tone:"] = "\uD83E\uDDCE\uD83C\uDFFC\u200D♂️", + [":man_kneeling_medium_skin_tone:"] = "\uD83E\uDDCE\uD83C\uDFFD\u200D♂️", + [":man_kneeling_tone1:"] = "\uD83E\uDDCE\uD83C\uDFFB\u200D♂️", + [":man_kneeling_tone2:"] = "\uD83E\uDDCE\uD83C\uDFFC\u200D♂️", + [":man_kneeling_tone3:"] = "\uD83E\uDDCE\uD83C\uDFFD\u200D♂️", + [":man_kneeling_tone4:"] = "\uD83E\uDDCE\uD83C\uDFFE\u200D♂️", + [":man_kneeling_tone5:"] = "\uD83E\uDDCE\uD83C\uDFFF\u200D♂️", + [":man_lifting_weights:"] = "\uD83C\uDFCB️\u200D♂️", + [":man_lifting_weights::skin-tone-1:"] = "\uD83C\uDFCB\uD83C\uDFFB\u200D♂️", + [":man_lifting_weights::skin-tone-2:"] = "\uD83C\uDFCB\uD83C\uDFFC\u200D♂️", + [":man_lifting_weights::skin-tone-3:"] = "\uD83C\uDFCB\uD83C\uDFFD\u200D♂️", + [":man_lifting_weights::skin-tone-4:"] = "\uD83C\uDFCB\uD83C\uDFFE\u200D♂️", + [":man_lifting_weights::skin-tone-5:"] = "\uD83C\uDFCB\uD83C\uDFFF\u200D♂️", + [":man_lifting_weights_dark_skin_tone:"] = "\uD83C\uDFCB\uD83C\uDFFF\u200D♂️", + [":man_lifting_weights_light_skin_tone:"] = "\uD83C\uDFCB\uD83C\uDFFB\u200D♂️", + [":man_lifting_weights_medium_dark_skin_tone:"] = "\uD83C\uDFCB\uD83C\uDFFE\u200D♂️", + [":man_lifting_weights_medium_light_skin_tone:"] = "\uD83C\uDFCB\uD83C\uDFFC\u200D♂️", + [":man_lifting_weights_medium_skin_tone:"] = "\uD83C\uDFCB\uD83C\uDFFD\u200D♂️", + [":man_lifting_weights_tone1:"] = "\uD83C\uDFCB\uD83C\uDFFB\u200D♂️", + [":man_lifting_weights_tone2:"] = "\uD83C\uDFCB\uD83C\uDFFC\u200D♂️", + [":man_lifting_weights_tone3:"] = "\uD83C\uDFCB\uD83C\uDFFD\u200D♂️", + [":man_lifting_weights_tone4:"] = "\uD83C\uDFCB\uD83C\uDFFE\u200D♂️", + [":man_lifting_weights_tone5:"] = "\uD83C\uDFCB\uD83C\uDFFF\u200D♂️", + [":man_mage:"] = "\uD83E\uDDD9\u200D♂️", + [":man_mage::skin-tone-1:"] = "\uD83E\uDDD9\uD83C\uDFFB\u200D♂️", + [":man_mage::skin-tone-2:"] = "\uD83E\uDDD9\uD83C\uDFFC\u200D♂️", + [":man_mage::skin-tone-3:"] = "\uD83E\uDDD9\uD83C\uDFFD\u200D♂️", + [":man_mage::skin-tone-4:"] = "\uD83E\uDDD9\uD83C\uDFFE\u200D♂️", + [":man_mage::skin-tone-5:"] = "\uD83E\uDDD9\uD83C\uDFFF\u200D♂️", + [":man_mage_dark_skin_tone:"] = "\uD83E\uDDD9\uD83C\uDFFF\u200D♂️", + [":man_mage_light_skin_tone:"] = "\uD83E\uDDD9\uD83C\uDFFB\u200D♂️", + [":man_mage_medium_dark_skin_tone:"] = "\uD83E\uDDD9\uD83C\uDFFE\u200D♂️", + [":man_mage_medium_light_skin_tone:"] = "\uD83E\uDDD9\uD83C\uDFFC\u200D♂️", + [":man_mage_medium_skin_tone:"] = "\uD83E\uDDD9\uD83C\uDFFD\u200D♂️", + [":man_mage_tone1:"] = "\uD83E\uDDD9\uD83C\uDFFB\u200D♂️", + [":man_mage_tone2:"] = "\uD83E\uDDD9\uD83C\uDFFC\u200D♂️", + [":man_mage_tone3:"] = "\uD83E\uDDD9\uD83C\uDFFD\u200D♂️", + [":man_mage_tone4:"] = "\uD83E\uDDD9\uD83C\uDFFE\u200D♂️", + [":man_mage_tone5:"] = "\uD83E\uDDD9\uD83C\uDFFF\u200D♂️", + [":man_mechanic:"] = "\uD83D\uDC68\u200D\uD83D\uDD27", + [":man_mechanic::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDD27", + [":man_mechanic::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDD27", + [":man_mechanic::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDD27", + [":man_mechanic::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDD27", + [":man_mechanic::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDD27", + [":man_mechanic_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDD27", + [":man_mechanic_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDD27", + [":man_mechanic_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDD27", + [":man_mechanic_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDD27", + [":man_mechanic_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDD27", + [":man_mechanic_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDD27", + [":man_mechanic_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDD27", + [":man_mechanic_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDD27", + [":man_mechanic_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDD27", + [":man_mechanic_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDD27", + [":man_mountain_biking:"] = "\uD83D\uDEB5\u200D♂️", + [":man_mountain_biking::skin-tone-1:"] = "\uD83D\uDEB5\uD83C\uDFFB\u200D♂️", + [":man_mountain_biking::skin-tone-2:"] = "\uD83D\uDEB5\uD83C\uDFFC\u200D♂️", + [":man_mountain_biking::skin-tone-3:"] = "\uD83D\uDEB5\uD83C\uDFFD\u200D♂️", + [":man_mountain_biking::skin-tone-4:"] = "\uD83D\uDEB5\uD83C\uDFFE\u200D♂️", + [":man_mountain_biking::skin-tone-5:"] = "\uD83D\uDEB5\uD83C\uDFFF\u200D♂️", + [":man_mountain_biking_dark_skin_tone:"] = "\uD83D\uDEB5\uD83C\uDFFF\u200D♂️", + [":man_mountain_biking_light_skin_tone:"] = "\uD83D\uDEB5\uD83C\uDFFB\u200D♂️", + [":man_mountain_biking_medium_dark_skin_tone:"] = "\uD83D\uDEB5\uD83C\uDFFE\u200D♂️", + [":man_mountain_biking_medium_light_skin_tone:"] = "\uD83D\uDEB5\uD83C\uDFFC\u200D♂️", + [":man_mountain_biking_medium_skin_tone:"] = "\uD83D\uDEB5\uD83C\uDFFD\u200D♂️", + [":man_mountain_biking_tone1:"] = "\uD83D\uDEB5\uD83C\uDFFB\u200D♂️", + [":man_mountain_biking_tone2:"] = "\uD83D\uDEB5\uD83C\uDFFC\u200D♂️", + [":man_mountain_biking_tone3:"] = "\uD83D\uDEB5\uD83C\uDFFD\u200D♂️", + [":man_mountain_biking_tone4:"] = "\uD83D\uDEB5\uD83C\uDFFE\u200D♂️", + [":man_mountain_biking_tone5:"] = "\uD83D\uDEB5\uD83C\uDFFF\u200D♂️", + [":man_office_worker:"] = "\uD83D\uDC68\u200D\uD83D\uDCBC", + [":man_office_worker::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDCBC", + [":man_office_worker::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDCBC", + [":man_office_worker::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDCBC", + [":man_office_worker::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDCBC", + [":man_office_worker::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDCBC", + [":man_office_worker_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDCBC", + [":man_office_worker_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDCBC", + [":man_office_worker_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDCBC", + [":man_office_worker_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDCBC", + [":man_office_worker_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDCBC", + [":man_office_worker_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDCBC", + [":man_office_worker_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDCBC", + [":man_office_worker_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDCBC", + [":man_office_worker_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDCBC", + [":man_office_worker_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDCBC", + [":man_pilot:"] = "\uD83D\uDC68\u200D✈️", + [":man_pilot::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D✈️", + [":man_pilot::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D✈️", + [":man_pilot::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D✈️", + [":man_pilot::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D✈️", + [":man_pilot::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D✈️", + [":man_pilot_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D✈️", + [":man_pilot_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D✈️", + [":man_pilot_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D✈️", + [":man_pilot_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D✈️", + [":man_pilot_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D✈️", + [":man_pilot_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D✈️", + [":man_pilot_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D✈️", + [":man_pilot_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D✈️", + [":man_pilot_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D✈️", + [":man_pilot_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D✈️", + [":man_playing_handball:"] = "\uD83E\uDD3E\u200D♂️", + [":man_playing_handball::skin-tone-1:"] = "\uD83E\uDD3E\uD83C\uDFFB\u200D♂️", + [":man_playing_handball::skin-tone-2:"] = "\uD83E\uDD3E\uD83C\uDFFC\u200D♂️", + [":man_playing_handball::skin-tone-3:"] = "\uD83E\uDD3E\uD83C\uDFFD\u200D♂️", + [":man_playing_handball::skin-tone-4:"] = "\uD83E\uDD3E\uD83C\uDFFE\u200D♂️", + [":man_playing_handball::skin-tone-5:"] = "\uD83E\uDD3E\uD83C\uDFFF\u200D♂️", + [":man_playing_handball_dark_skin_tone:"] = "\uD83E\uDD3E\uD83C\uDFFF\u200D♂️", + [":man_playing_handball_light_skin_tone:"] = "\uD83E\uDD3E\uD83C\uDFFB\u200D♂️", + [":man_playing_handball_medium_dark_skin_tone:"] = "\uD83E\uDD3E\uD83C\uDFFE\u200D♂️", + [":man_playing_handball_medium_light_skin_tone:"] = "\uD83E\uDD3E\uD83C\uDFFC\u200D♂️", + [":man_playing_handball_medium_skin_tone:"] = "\uD83E\uDD3E\uD83C\uDFFD\u200D♂️", + [":man_playing_handball_tone1:"] = "\uD83E\uDD3E\uD83C\uDFFB\u200D♂️", + [":man_playing_handball_tone2:"] = "\uD83E\uDD3E\uD83C\uDFFC\u200D♂️", + [":man_playing_handball_tone3:"] = "\uD83E\uDD3E\uD83C\uDFFD\u200D♂️", + [":man_playing_handball_tone4:"] = "\uD83E\uDD3E\uD83C\uDFFE\u200D♂️", + [":man_playing_handball_tone5:"] = "\uD83E\uDD3E\uD83C\uDFFF\u200D♂️", + [":man_playing_water_polo:"] = "\uD83E\uDD3D\u200D♂️", + [":man_playing_water_polo::skin-tone-1:"] = "\uD83E\uDD3D\uD83C\uDFFB\u200D♂️", + [":man_playing_water_polo::skin-tone-2:"] = "\uD83E\uDD3D\uD83C\uDFFC\u200D♂️", + [":man_playing_water_polo::skin-tone-3:"] = "\uD83E\uDD3D\uD83C\uDFFD\u200D♂️", + [":man_playing_water_polo::skin-tone-4:"] = "\uD83E\uDD3D\uD83C\uDFFE\u200D♂️", + [":man_playing_water_polo::skin-tone-5:"] = "\uD83E\uDD3D\uD83C\uDFFF\u200D♂️", + [":man_playing_water_polo_dark_skin_tone:"] = "\uD83E\uDD3D\uD83C\uDFFF\u200D♂️", + [":man_playing_water_polo_light_skin_tone:"] = "\uD83E\uDD3D\uD83C\uDFFB\u200D♂️", + [":man_playing_water_polo_medium_dark_skin_tone:"] = "\uD83E\uDD3D\uD83C\uDFFE\u200D♂️", + [":man_playing_water_polo_medium_light_skin_tone:"] = "\uD83E\uDD3D\uD83C\uDFFC\u200D♂️", + [":man_playing_water_polo_medium_skin_tone:"] = "\uD83E\uDD3D\uD83C\uDFFD\u200D♂️", + [":man_playing_water_polo_tone1:"] = "\uD83E\uDD3D\uD83C\uDFFB\u200D♂️", + [":man_playing_water_polo_tone2:"] = "\uD83E\uDD3D\uD83C\uDFFC\u200D♂️", + [":man_playing_water_polo_tone3:"] = "\uD83E\uDD3D\uD83C\uDFFD\u200D♂️", + [":man_playing_water_polo_tone4:"] = "\uD83E\uDD3D\uD83C\uDFFE\u200D♂️", + [":man_playing_water_polo_tone5:"] = "\uD83E\uDD3D\uD83C\uDFFF\u200D♂️", + [":man_police_officer:"] = "\uD83D\uDC6E\u200D♂️", + [":man_police_officer::skin-tone-1:"] = "\uD83D\uDC6E\uD83C\uDFFB\u200D♂️", + [":man_police_officer::skin-tone-2:"] = "\uD83D\uDC6E\uD83C\uDFFC\u200D♂️", + [":man_police_officer::skin-tone-3:"] = "\uD83D\uDC6E\uD83C\uDFFD\u200D♂️", + [":man_police_officer::skin-tone-4:"] = "\uD83D\uDC6E\uD83C\uDFFE\u200D♂️", + [":man_police_officer::skin-tone-5:"] = "\uD83D\uDC6E\uD83C\uDFFF\u200D♂️", + [":man_police_officer_dark_skin_tone:"] = "\uD83D\uDC6E\uD83C\uDFFF\u200D♂️", + [":man_police_officer_light_skin_tone:"] = "\uD83D\uDC6E\uD83C\uDFFB\u200D♂️", + [":man_police_officer_medium_dark_skin_tone:"] = "\uD83D\uDC6E\uD83C\uDFFE\u200D♂️", + [":man_police_officer_medium_light_skin_tone:"] = "\uD83D\uDC6E\uD83C\uDFFC\u200D♂️", + [":man_police_officer_medium_skin_tone:"] = "\uD83D\uDC6E\uD83C\uDFFD\u200D♂️", + [":man_police_officer_tone1:"] = "\uD83D\uDC6E\uD83C\uDFFB\u200D♂️", + [":man_police_officer_tone2:"] = "\uD83D\uDC6E\uD83C\uDFFC\u200D♂️", + [":man_police_officer_tone3:"] = "\uD83D\uDC6E\uD83C\uDFFD\u200D♂️", + [":man_police_officer_tone4:"] = "\uD83D\uDC6E\uD83C\uDFFE\u200D♂️", + [":man_police_officer_tone5:"] = "\uD83D\uDC6E\uD83C\uDFFF\u200D♂️", + [":man_pouting:"] = "\uD83D\uDE4E\u200D♂️", + [":man_pouting::skin-tone-1:"] = "\uD83D\uDE4E\uD83C\uDFFB\u200D♂️", + [":man_pouting::skin-tone-2:"] = "\uD83D\uDE4E\uD83C\uDFFC\u200D♂️", + [":man_pouting::skin-tone-3:"] = "\uD83D\uDE4E\uD83C\uDFFD\u200D♂️", + [":man_pouting::skin-tone-4:"] = "\uD83D\uDE4E\uD83C\uDFFE\u200D♂️", + [":man_pouting::skin-tone-5:"] = "\uD83D\uDE4E\uD83C\uDFFF\u200D♂️", + [":man_pouting_dark_skin_tone:"] = "\uD83D\uDE4E\uD83C\uDFFF\u200D♂️", + [":man_pouting_light_skin_tone:"] = "\uD83D\uDE4E\uD83C\uDFFB\u200D♂️", + [":man_pouting_medium_dark_skin_tone:"] = "\uD83D\uDE4E\uD83C\uDFFE\u200D♂️", + [":man_pouting_medium_light_skin_tone:"] = "\uD83D\uDE4E\uD83C\uDFFC\u200D♂️", + [":man_pouting_medium_skin_tone:"] = "\uD83D\uDE4E\uD83C\uDFFD\u200D♂️", + [":man_pouting_tone1:"] = "\uD83D\uDE4E\uD83C\uDFFB\u200D♂️", + [":man_pouting_tone2:"] = "\uD83D\uDE4E\uD83C\uDFFC\u200D♂️", + [":man_pouting_tone3:"] = "\uD83D\uDE4E\uD83C\uDFFD\u200D♂️", + [":man_pouting_tone4:"] = "\uD83D\uDE4E\uD83C\uDFFE\u200D♂️", + [":man_pouting_tone5:"] = "\uD83D\uDE4E\uD83C\uDFFF\u200D♂️", + [":man_raising_hand:"] = "\uD83D\uDE4B\u200D♂️", + [":man_raising_hand::skin-tone-1:"] = "\uD83D\uDE4B\uD83C\uDFFB\u200D♂️", + [":man_raising_hand::skin-tone-2:"] = "\uD83D\uDE4B\uD83C\uDFFC\u200D♂️", + [":man_raising_hand::skin-tone-3:"] = "\uD83D\uDE4B\uD83C\uDFFD\u200D♂️", + [":man_raising_hand::skin-tone-4:"] = "\uD83D\uDE4B\uD83C\uDFFE\u200D♂️", + [":man_raising_hand::skin-tone-5:"] = "\uD83D\uDE4B\uD83C\uDFFF\u200D♂️", + [":man_raising_hand_dark_skin_tone:"] = "\uD83D\uDE4B\uD83C\uDFFF\u200D♂️", + [":man_raising_hand_light_skin_tone:"] = "\uD83D\uDE4B\uD83C\uDFFB\u200D♂️", + [":man_raising_hand_medium_dark_skin_tone:"] = "\uD83D\uDE4B\uD83C\uDFFE\u200D♂️", + [":man_raising_hand_medium_light_skin_tone:"] = "\uD83D\uDE4B\uD83C\uDFFC\u200D♂️", + [":man_raising_hand_medium_skin_tone:"] = "\uD83D\uDE4B\uD83C\uDFFD\u200D♂️", + [":man_raising_hand_tone1:"] = "\uD83D\uDE4B\uD83C\uDFFB\u200D♂️", + [":man_raising_hand_tone2:"] = "\uD83D\uDE4B\uD83C\uDFFC\u200D♂️", + [":man_raising_hand_tone3:"] = "\uD83D\uDE4B\uD83C\uDFFD\u200D♂️", + [":man_raising_hand_tone4:"] = "\uD83D\uDE4B\uD83C\uDFFE\u200D♂️", + [":man_raising_hand_tone5:"] = "\uD83D\uDE4B\uD83C\uDFFF\u200D♂️", + [":man_red_haired:"] = "\uD83D\uDC68\u200D\uD83E\uDDB0", + [":man_red_haired::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDB0", + [":man_red_haired::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDB0", + [":man_red_haired::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDB0", + [":man_red_haired::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDB0", + [":man_red_haired::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDB0", + [":man_red_haired_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDB0", + [":man_red_haired_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDB0", + [":man_red_haired_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDB0", + [":man_red_haired_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDB0", + [":man_red_haired_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDB0", + [":man_red_haired_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDB0", + [":man_red_haired_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDB0", + [":man_red_haired_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDB0", + [":man_red_haired_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDB0", + [":man_red_haired_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDB0", + [":man_rowing_boat:"] = "\uD83D\uDEA3\u200D♂️", + [":man_rowing_boat::skin-tone-1:"] = "\uD83D\uDEA3\uD83C\uDFFB\u200D♂️", + [":man_rowing_boat::skin-tone-2:"] = "\uD83D\uDEA3\uD83C\uDFFC\u200D♂️", + [":man_rowing_boat::skin-tone-3:"] = "\uD83D\uDEA3\uD83C\uDFFD\u200D♂️", + [":man_rowing_boat::skin-tone-4:"] = "\uD83D\uDEA3\uD83C\uDFFE\u200D♂️", + [":man_rowing_boat::skin-tone-5:"] = "\uD83D\uDEA3\uD83C\uDFFF\u200D♂️", + [":man_rowing_boat_dark_skin_tone:"] = "\uD83D\uDEA3\uD83C\uDFFF\u200D♂️", + [":man_rowing_boat_light_skin_tone:"] = "\uD83D\uDEA3\uD83C\uDFFB\u200D♂️", + [":man_rowing_boat_medium_dark_skin_tone:"] = "\uD83D\uDEA3\uD83C\uDFFE\u200D♂️", + [":man_rowing_boat_medium_light_skin_tone:"] = "\uD83D\uDEA3\uD83C\uDFFC\u200D♂️", + [":man_rowing_boat_medium_skin_tone:"] = "\uD83D\uDEA3\uD83C\uDFFD\u200D♂️", + [":man_rowing_boat_tone1:"] = "\uD83D\uDEA3\uD83C\uDFFB\u200D♂️", + [":man_rowing_boat_tone2:"] = "\uD83D\uDEA3\uD83C\uDFFC\u200D♂️", + [":man_rowing_boat_tone3:"] = "\uD83D\uDEA3\uD83C\uDFFD\u200D♂️", + [":man_rowing_boat_tone4:"] = "\uD83D\uDEA3\uD83C\uDFFE\u200D♂️", + [":man_rowing_boat_tone5:"] = "\uD83D\uDEA3\uD83C\uDFFF\u200D♂️", + [":man_running:"] = "\uD83C\uDFC3\u200D♂️", + [":man_running::skin-tone-1:"] = "\uD83C\uDFC3\uD83C\uDFFB\u200D♂️", + [":man_running::skin-tone-2:"] = "\uD83C\uDFC3\uD83C\uDFFC\u200D♂️", + [":man_running::skin-tone-3:"] = "\uD83C\uDFC3\uD83C\uDFFD\u200D♂️", + [":man_running::skin-tone-4:"] = "\uD83C\uDFC3\uD83C\uDFFE\u200D♂️", + [":man_running::skin-tone-5:"] = "\uD83C\uDFC3\uD83C\uDFFF\u200D♂️", + [":man_running_dark_skin_tone:"] = "\uD83C\uDFC3\uD83C\uDFFF\u200D♂️", + [":man_running_light_skin_tone:"] = "\uD83C\uDFC3\uD83C\uDFFB\u200D♂️", + [":man_running_medium_dark_skin_tone:"] = "\uD83C\uDFC3\uD83C\uDFFE\u200D♂️", + [":man_running_medium_light_skin_tone:"] = "\uD83C\uDFC3\uD83C\uDFFC\u200D♂️", + [":man_running_medium_skin_tone:"] = "\uD83C\uDFC3\uD83C\uDFFD\u200D♂️", + [":man_running_tone1:"] = "\uD83C\uDFC3\uD83C\uDFFB\u200D♂️", + [":man_running_tone2:"] = "\uD83C\uDFC3\uD83C\uDFFC\u200D♂️", + [":man_running_tone3:"] = "\uD83C\uDFC3\uD83C\uDFFD\u200D♂️", + [":man_running_tone4:"] = "\uD83C\uDFC3\uD83C\uDFFE\u200D♂️", + [":man_running_tone5:"] = "\uD83C\uDFC3\uD83C\uDFFF\u200D♂️", + [":man_scientist:"] = "\uD83D\uDC68\u200D\uD83D\uDD2C", + [":man_scientist::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDD2C", + [":man_scientist::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDD2C", + [":man_scientist::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDD2C", + [":man_scientist::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDD2C", + [":man_scientist::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDD2C", + [":man_scientist_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDD2C", + [":man_scientist_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDD2C", + [":man_scientist_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDD2C", + [":man_scientist_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDD2C", + [":man_scientist_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDD2C", + [":man_scientist_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDD2C", + [":man_scientist_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDD2C", + [":man_scientist_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDD2C", + [":man_scientist_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDD2C", + [":man_scientist_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDD2C", + [":man_shrugging:"] = "\uD83E\uDD37\u200D♂️", + [":man_shrugging::skin-tone-1:"] = "\uD83E\uDD37\uD83C\uDFFB\u200D♂️", + [":man_shrugging::skin-tone-2:"] = "\uD83E\uDD37\uD83C\uDFFC\u200D♂️", + [":man_shrugging::skin-tone-3:"] = "\uD83E\uDD37\uD83C\uDFFD\u200D♂️", + [":man_shrugging::skin-tone-4:"] = "\uD83E\uDD37\uD83C\uDFFE\u200D♂️", + [":man_shrugging::skin-tone-5:"] = "\uD83E\uDD37\uD83C\uDFFF\u200D♂️", + [":man_shrugging_dark_skin_tone:"] = "\uD83E\uDD37\uD83C\uDFFF\u200D♂️", + [":man_shrugging_light_skin_tone:"] = "\uD83E\uDD37\uD83C\uDFFB\u200D♂️", + [":man_shrugging_medium_dark_skin_tone:"] = "\uD83E\uDD37\uD83C\uDFFE\u200D♂️", + [":man_shrugging_medium_light_skin_tone:"] = "\uD83E\uDD37\uD83C\uDFFC\u200D♂️", + [":man_shrugging_medium_skin_tone:"] = "\uD83E\uDD37\uD83C\uDFFD\u200D♂️", + [":man_shrugging_tone1:"] = "\uD83E\uDD37\uD83C\uDFFB\u200D♂️", + [":man_shrugging_tone2:"] = "\uD83E\uDD37\uD83C\uDFFC\u200D♂️", + [":man_shrugging_tone3:"] = "\uD83E\uDD37\uD83C\uDFFD\u200D♂️", + [":man_shrugging_tone4:"] = "\uD83E\uDD37\uD83C\uDFFE\u200D♂️", + [":man_shrugging_tone5:"] = "\uD83E\uDD37\uD83C\uDFFF\u200D♂️", + [":man_singer:"] = "\uD83D\uDC68\u200D\uD83C\uDFA4", + [":man_singer::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDFA4", + [":man_singer::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDFA4", + [":man_singer::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDFA4", + [":man_singer::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDFA4", + [":man_singer::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDFA4", + [":man_singer_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDFA4", + [":man_singer_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDFA4", + [":man_singer_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDFA4", + [":man_singer_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDFA4", + [":man_singer_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDFA4", + [":man_singer_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDFA4", + [":man_singer_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDFA4", + [":man_singer_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDFA4", + [":man_singer_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDFA4", + [":man_singer_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDFA4", + [":man_standing:"] = "\uD83E\uDDCD\u200D♂️", + [":man_standing::skin-tone-1:"] = "\uD83E\uDDCD\uD83C\uDFFB\u200D♂️", + [":man_standing::skin-tone-2:"] = "\uD83E\uDDCD\uD83C\uDFFC\u200D♂️", + [":man_standing::skin-tone-3:"] = "\uD83E\uDDCD\uD83C\uDFFD\u200D♂️", + [":man_standing::skin-tone-4:"] = "\uD83E\uDDCD\uD83C\uDFFE\u200D♂️", + [":man_standing::skin-tone-5:"] = "\uD83E\uDDCD\uD83C\uDFFF\u200D♂️", + [":man_standing_dark_skin_tone:"] = "\uD83E\uDDCD\uD83C\uDFFF\u200D♂️", + [":man_standing_light_skin_tone:"] = "\uD83E\uDDCD\uD83C\uDFFB\u200D♂️", + [":man_standing_medium_dark_skin_tone:"] = "\uD83E\uDDCD\uD83C\uDFFE\u200D♂️", + [":man_standing_medium_light_skin_tone:"] = "\uD83E\uDDCD\uD83C\uDFFC\u200D♂️", + [":man_standing_medium_skin_tone:"] = "\uD83E\uDDCD\uD83C\uDFFD\u200D♂️", + [":man_standing_tone1:"] = "\uD83E\uDDCD\uD83C\uDFFB\u200D♂️", + [":man_standing_tone2:"] = "\uD83E\uDDCD\uD83C\uDFFC\u200D♂️", + [":man_standing_tone3:"] = "\uD83E\uDDCD\uD83C\uDFFD\u200D♂️", + [":man_standing_tone4:"] = "\uD83E\uDDCD\uD83C\uDFFE\u200D♂️", + [":man_standing_tone5:"] = "\uD83E\uDDCD\uD83C\uDFFF\u200D♂️", + [":man_student:"] = "\uD83D\uDC68\u200D\uD83C\uDF93", + [":man_student::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDF93", + [":man_student::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDF93", + [":man_student::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDF93", + [":man_student::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDF93", + [":man_student::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDF93", + [":man_student_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDF93", + [":man_student_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDF93", + [":man_student_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDF93", + [":man_student_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDF93", + [":man_student_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDF93", + [":man_student_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDF93", + [":man_student_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDF93", + [":man_student_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDF93", + [":man_student_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDF93", + [":man_student_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDF93", + [":man_superhero:"] = "\uD83E\uDDB8\u200D♂️", + [":man_superhero::skin-tone-1:"] = "\uD83E\uDDB8\uD83C\uDFFB\u200D♂️", + [":man_superhero::skin-tone-2:"] = "\uD83E\uDDB8\uD83C\uDFFC\u200D♂️", + [":man_superhero::skin-tone-3:"] = "\uD83E\uDDB8\uD83C\uDFFD\u200D♂️", + [":man_superhero::skin-tone-4:"] = "\uD83E\uDDB8\uD83C\uDFFE\u200D♂️", + [":man_superhero::skin-tone-5:"] = "\uD83E\uDDB8\uD83C\uDFFF\u200D♂️", + [":man_superhero_dark_skin_tone:"] = "\uD83E\uDDB8\uD83C\uDFFF\u200D♂️", + [":man_superhero_light_skin_tone:"] = "\uD83E\uDDB8\uD83C\uDFFB\u200D♂️", + [":man_superhero_medium_dark_skin_tone:"] = "\uD83E\uDDB8\uD83C\uDFFE\u200D♂️", + [":man_superhero_medium_light_skin_tone:"] = "\uD83E\uDDB8\uD83C\uDFFC\u200D♂️", + [":man_superhero_medium_skin_tone:"] = "\uD83E\uDDB8\uD83C\uDFFD\u200D♂️", + [":man_superhero_tone1:"] = "\uD83E\uDDB8\uD83C\uDFFB\u200D♂️", + [":man_superhero_tone2:"] = "\uD83E\uDDB8\uD83C\uDFFC\u200D♂️", + [":man_superhero_tone3:"] = "\uD83E\uDDB8\uD83C\uDFFD\u200D♂️", + [":man_superhero_tone4:"] = "\uD83E\uDDB8\uD83C\uDFFE\u200D♂️", + [":man_superhero_tone5:"] = "\uD83E\uDDB8\uD83C\uDFFF\u200D♂️", + [":man_supervillain:"] = "\uD83E\uDDB9\u200D♂️", + [":man_supervillain::skin-tone-1:"] = "\uD83E\uDDB9\uD83C\uDFFB\u200D♂️", + [":man_supervillain::skin-tone-2:"] = "\uD83E\uDDB9\uD83C\uDFFC\u200D♂️", + [":man_supervillain::skin-tone-3:"] = "\uD83E\uDDB9\uD83C\uDFFD\u200D♂️", + [":man_supervillain::skin-tone-4:"] = "\uD83E\uDDB9\uD83C\uDFFE\u200D♂️", + [":man_supervillain::skin-tone-5:"] = "\uD83E\uDDB9\uD83C\uDFFF\u200D♂️", + [":man_supervillain_dark_skin_tone:"] = "\uD83E\uDDB9\uD83C\uDFFF\u200D♂️", + [":man_supervillain_light_skin_tone:"] = "\uD83E\uDDB9\uD83C\uDFFB\u200D♂️", + [":man_supervillain_medium_dark_skin_tone:"] = "\uD83E\uDDB9\uD83C\uDFFE\u200D♂️", + [":man_supervillain_medium_light_skin_tone:"] = "\uD83E\uDDB9\uD83C\uDFFC\u200D♂️", + [":man_supervillain_medium_skin_tone:"] = "\uD83E\uDDB9\uD83C\uDFFD\u200D♂️", + [":man_supervillain_tone1:"] = "\uD83E\uDDB9\uD83C\uDFFB\u200D♂️", + [":man_supervillain_tone2:"] = "\uD83E\uDDB9\uD83C\uDFFC\u200D♂️", + [":man_supervillain_tone3:"] = "\uD83E\uDDB9\uD83C\uDFFD\u200D♂️", + [":man_supervillain_tone4:"] = "\uD83E\uDDB9\uD83C\uDFFE\u200D♂️", + [":man_supervillain_tone5:"] = "\uD83E\uDDB9\uD83C\uDFFF\u200D♂️", + [":man_surfing:"] = "\uD83C\uDFC4\u200D♂️", + [":man_surfing::skin-tone-1:"] = "\uD83C\uDFC4\uD83C\uDFFB\u200D♂️", + [":man_surfing::skin-tone-2:"] = "\uD83C\uDFC4\uD83C\uDFFC\u200D♂️", + [":man_surfing::skin-tone-3:"] = "\uD83C\uDFC4\uD83C\uDFFD\u200D♂️", + [":man_surfing::skin-tone-4:"] = "\uD83C\uDFC4\uD83C\uDFFE\u200D♂️", + [":man_surfing::skin-tone-5:"] = "\uD83C\uDFC4\uD83C\uDFFF\u200D♂️", + [":man_surfing_dark_skin_tone:"] = "\uD83C\uDFC4\uD83C\uDFFF\u200D♂️", + [":man_surfing_light_skin_tone:"] = "\uD83C\uDFC4\uD83C\uDFFB\u200D♂️", + [":man_surfing_medium_dark_skin_tone:"] = "\uD83C\uDFC4\uD83C\uDFFE\u200D♂️", + [":man_surfing_medium_light_skin_tone:"] = "\uD83C\uDFC4\uD83C\uDFFC\u200D♂️", + [":man_surfing_medium_skin_tone:"] = "\uD83C\uDFC4\uD83C\uDFFD\u200D♂️", + [":man_surfing_tone1:"] = "\uD83C\uDFC4\uD83C\uDFFB\u200D♂️", + [":man_surfing_tone2:"] = "\uD83C\uDFC4\uD83C\uDFFC\u200D♂️", + [":man_surfing_tone3:"] = "\uD83C\uDFC4\uD83C\uDFFD\u200D♂️", + [":man_surfing_tone4:"] = "\uD83C\uDFC4\uD83C\uDFFE\u200D♂️", + [":man_surfing_tone5:"] = "\uD83C\uDFC4\uD83C\uDFFF\u200D♂️", + [":man_swimming:"] = "\uD83C\uDFCA\u200D♂️", + [":man_swimming::skin-tone-1:"] = "\uD83C\uDFCA\uD83C\uDFFB\u200D♂️", + [":man_swimming::skin-tone-2:"] = "\uD83C\uDFCA\uD83C\uDFFC\u200D♂️", + [":man_swimming::skin-tone-3:"] = "\uD83C\uDFCA\uD83C\uDFFD\u200D♂️", + [":man_swimming::skin-tone-4:"] = "\uD83C\uDFCA\uD83C\uDFFE\u200D♂️", + [":man_swimming::skin-tone-5:"] = "\uD83C\uDFCA\uD83C\uDFFF\u200D♂️", + [":man_swimming_dark_skin_tone:"] = "\uD83C\uDFCA\uD83C\uDFFF\u200D♂️", + [":man_swimming_light_skin_tone:"] = "\uD83C\uDFCA\uD83C\uDFFB\u200D♂️", + [":man_swimming_medium_dark_skin_tone:"] = "\uD83C\uDFCA\uD83C\uDFFE\u200D♂️", + [":man_swimming_medium_light_skin_tone:"] = "\uD83C\uDFCA\uD83C\uDFFC\u200D♂️", + [":man_swimming_medium_skin_tone:"] = "\uD83C\uDFCA\uD83C\uDFFD\u200D♂️", + [":man_swimming_tone1:"] = "\uD83C\uDFCA\uD83C\uDFFB\u200D♂️", + [":man_swimming_tone2:"] = "\uD83C\uDFCA\uD83C\uDFFC\u200D♂️", + [":man_swimming_tone3:"] = "\uD83C\uDFCA\uD83C\uDFFD\u200D♂️", + [":man_swimming_tone4:"] = "\uD83C\uDFCA\uD83C\uDFFE\u200D♂️", + [":man_swimming_tone5:"] = "\uD83C\uDFCA\uD83C\uDFFF\u200D♂️", + [":man_teacher:"] = "\uD83D\uDC68\u200D\uD83C\uDFEB", + [":man_teacher::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDFEB", + [":man_teacher::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDFEB", + [":man_teacher::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDFEB", + [":man_teacher::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDFEB", + [":man_teacher::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDFEB", + [":man_teacher_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDFEB", + [":man_teacher_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDFEB", + [":man_teacher_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDFEB", + [":man_teacher_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDFEB", + [":man_teacher_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDFEB", + [":man_teacher_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83C\uDFEB", + [":man_teacher_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83C\uDFEB", + [":man_teacher_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83C\uDFEB", + [":man_teacher_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83C\uDFEB", + [":man_teacher_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83C\uDFEB", + [":man_technologist:"] = "\uD83D\uDC68\u200D\uD83D\uDCBB", + [":man_technologist::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDCBB", + [":man_technologist::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDCBB", + [":man_technologist::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDCBB", + [":man_technologist::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDCBB", + [":man_technologist::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDCBB", + [":man_technologist_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDCBB", + [":man_technologist_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDCBB", + [":man_technologist_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDCBB", + [":man_technologist_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDCBB", + [":man_technologist_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDCBB", + [":man_technologist_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83D\uDCBB", + [":man_technologist_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83D\uDCBB", + [":man_technologist_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83D\uDCBB", + [":man_technologist_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83D\uDCBB", + [":man_technologist_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83D\uDCBB", + [":man_tipping_hand:"] = "\uD83D\uDC81\u200D♂️", + [":man_tipping_hand::skin-tone-1:"] = "\uD83D\uDC81\uD83C\uDFFB\u200D♂️", + [":man_tipping_hand::skin-tone-2:"] = "\uD83D\uDC81\uD83C\uDFFC\u200D♂️", + [":man_tipping_hand::skin-tone-3:"] = "\uD83D\uDC81\uD83C\uDFFD\u200D♂️", + [":man_tipping_hand::skin-tone-4:"] = "\uD83D\uDC81\uD83C\uDFFE\u200D♂️", + [":man_tipping_hand::skin-tone-5:"] = "\uD83D\uDC81\uD83C\uDFFF\u200D♂️", + [":man_tipping_hand_dark_skin_tone:"] = "\uD83D\uDC81\uD83C\uDFFF\u200D♂️", + [":man_tipping_hand_light_skin_tone:"] = "\uD83D\uDC81\uD83C\uDFFB\u200D♂️", + [":man_tipping_hand_medium_dark_skin_tone:"] = "\uD83D\uDC81\uD83C\uDFFE\u200D♂️", + [":man_tipping_hand_medium_light_skin_tone:"] = "\uD83D\uDC81\uD83C\uDFFC\u200D♂️", + [":man_tipping_hand_medium_skin_tone:"] = "\uD83D\uDC81\uD83C\uDFFD\u200D♂️", + [":man_tipping_hand_tone1:"] = "\uD83D\uDC81\uD83C\uDFFB\u200D♂️", + [":man_tipping_hand_tone2:"] = "\uD83D\uDC81\uD83C\uDFFC\u200D♂️", + [":man_tipping_hand_tone3:"] = "\uD83D\uDC81\uD83C\uDFFD\u200D♂️", + [":man_tipping_hand_tone4:"] = "\uD83D\uDC81\uD83C\uDFFE\u200D♂️", + [":man_tipping_hand_tone5:"] = "\uD83D\uDC81\uD83C\uDFFF\u200D♂️", + [":man_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB", + [":man_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC", + [":man_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD", + [":man_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE", + [":man_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF", + [":man_vampire:"] = "\uD83E\uDDDB\u200D♂️", + [":man_vampire::skin-tone-1:"] = "\uD83E\uDDDB\uD83C\uDFFB\u200D♂️", + [":man_vampire::skin-tone-2:"] = "\uD83E\uDDDB\uD83C\uDFFC\u200D♂️", + [":man_vampire::skin-tone-3:"] = "\uD83E\uDDDB\uD83C\uDFFD\u200D♂️", + [":man_vampire::skin-tone-4:"] = "\uD83E\uDDDB\uD83C\uDFFE\u200D♂️", + [":man_vampire::skin-tone-5:"] = "\uD83E\uDDDB\uD83C\uDFFF\u200D♂️", + [":man_vampire_dark_skin_tone:"] = "\uD83E\uDDDB\uD83C\uDFFF\u200D♂️", + [":man_vampire_light_skin_tone:"] = "\uD83E\uDDDB\uD83C\uDFFB\u200D♂️", + [":man_vampire_medium_dark_skin_tone:"] = "\uD83E\uDDDB\uD83C\uDFFE\u200D♂️", + [":man_vampire_medium_light_skin_tone:"] = "\uD83E\uDDDB\uD83C\uDFFC\u200D♂️", + [":man_vampire_medium_skin_tone:"] = "\uD83E\uDDDB\uD83C\uDFFD\u200D♂️", + [":man_vampire_tone1:"] = "\uD83E\uDDDB\uD83C\uDFFB\u200D♂️", + [":man_vampire_tone2:"] = "\uD83E\uDDDB\uD83C\uDFFC\u200D♂️", + [":man_vampire_tone3:"] = "\uD83E\uDDDB\uD83C\uDFFD\u200D♂️", + [":man_vampire_tone4:"] = "\uD83E\uDDDB\uD83C\uDFFE\u200D♂️", + [":man_vampire_tone5:"] = "\uD83E\uDDDB\uD83C\uDFFF\u200D♂️", + [":man_walking:"] = "\uD83D\uDEB6\u200D♂️", + [":man_walking::skin-tone-1:"] = "\uD83D\uDEB6\uD83C\uDFFB\u200D♂️", + [":man_walking::skin-tone-2:"] = "\uD83D\uDEB6\uD83C\uDFFC\u200D♂️", + [":man_walking::skin-tone-3:"] = "\uD83D\uDEB6\uD83C\uDFFD\u200D♂️", + [":man_walking::skin-tone-4:"] = "\uD83D\uDEB6\uD83C\uDFFE\u200D♂️", + [":man_walking::skin-tone-5:"] = "\uD83D\uDEB6\uD83C\uDFFF\u200D♂️", + [":man_walking_dark_skin_tone:"] = "\uD83D\uDEB6\uD83C\uDFFF\u200D♂️", + [":man_walking_light_skin_tone:"] = "\uD83D\uDEB6\uD83C\uDFFB\u200D♂️", + [":man_walking_medium_dark_skin_tone:"] = "\uD83D\uDEB6\uD83C\uDFFE\u200D♂️", + [":man_walking_medium_light_skin_tone:"] = "\uD83D\uDEB6\uD83C\uDFFC\u200D♂️", + [":man_walking_medium_skin_tone:"] = "\uD83D\uDEB6\uD83C\uDFFD\u200D♂️", + [":man_walking_tone1:"] = "\uD83D\uDEB6\uD83C\uDFFB\u200D♂️", + [":man_walking_tone2:"] = "\uD83D\uDEB6\uD83C\uDFFC\u200D♂️", + [":man_walking_tone3:"] = "\uD83D\uDEB6\uD83C\uDFFD\u200D♂️", + [":man_walking_tone4:"] = "\uD83D\uDEB6\uD83C\uDFFE\u200D♂️", + [":man_walking_tone5:"] = "\uD83D\uDEB6\uD83C\uDFFF\u200D♂️", + [":man_wearing_turban:"] = "\uD83D\uDC73\u200D♂️", + [":man_wearing_turban::skin-tone-1:"] = "\uD83D\uDC73\uD83C\uDFFB\u200D♂️", + [":man_wearing_turban::skin-tone-2:"] = "\uD83D\uDC73\uD83C\uDFFC\u200D♂️", + [":man_wearing_turban::skin-tone-3:"] = "\uD83D\uDC73\uD83C\uDFFD\u200D♂️", + [":man_wearing_turban::skin-tone-4:"] = "\uD83D\uDC73\uD83C\uDFFE\u200D♂️", + [":man_wearing_turban::skin-tone-5:"] = "\uD83D\uDC73\uD83C\uDFFF\u200D♂️", + [":man_wearing_turban_dark_skin_tone:"] = "\uD83D\uDC73\uD83C\uDFFF\u200D♂️", + [":man_wearing_turban_light_skin_tone:"] = "\uD83D\uDC73\uD83C\uDFFB\u200D♂️", + [":man_wearing_turban_medium_dark_skin_tone:"] = "\uD83D\uDC73\uD83C\uDFFE\u200D♂️", + [":man_wearing_turban_medium_light_skin_tone:"] = "\uD83D\uDC73\uD83C\uDFFC\u200D♂️", + [":man_wearing_turban_medium_skin_tone:"] = "\uD83D\uDC73\uD83C\uDFFD\u200D♂️", + [":man_wearing_turban_tone1:"] = "\uD83D\uDC73\uD83C\uDFFB\u200D♂️", + [":man_wearing_turban_tone2:"] = "\uD83D\uDC73\uD83C\uDFFC\u200D♂️", + [":man_wearing_turban_tone3:"] = "\uD83D\uDC73\uD83C\uDFFD\u200D♂️", + [":man_wearing_turban_tone4:"] = "\uD83D\uDC73\uD83C\uDFFE\u200D♂️", + [":man_wearing_turban_tone5:"] = "\uD83D\uDC73\uD83C\uDFFF\u200D♂️", + [":man_white_haired:"] = "\uD83D\uDC68\u200D\uD83E\uDDB3", + [":man_white_haired::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDB3", + [":man_white_haired::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDB3", + [":man_white_haired::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDB3", + [":man_white_haired::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDB3", + [":man_white_haired::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDB3", + [":man_white_haired_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDB3", + [":man_white_haired_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDB3", + [":man_white_haired_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDB3", + [":man_white_haired_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDB3", + [":man_white_haired_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDB3", + [":man_white_haired_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDB3", + [":man_white_haired_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDB3", + [":man_white_haired_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDB3", + [":man_white_haired_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDB3", + [":man_white_haired_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDB3", + [":man_with_chinese_cap:"] = "\uD83D\uDC72", + [":man_with_chinese_cap::skin-tone-1:"] = "\uD83D\uDC72\uD83C\uDFFB", + [":man_with_chinese_cap::skin-tone-2:"] = "\uD83D\uDC72\uD83C\uDFFC", + [":man_with_chinese_cap::skin-tone-3:"] = "\uD83D\uDC72\uD83C\uDFFD", + [":man_with_chinese_cap::skin-tone-4:"] = "\uD83D\uDC72\uD83C\uDFFE", + [":man_with_chinese_cap::skin-tone-5:"] = "\uD83D\uDC72\uD83C\uDFFF", + [":man_with_chinese_cap_tone1:"] = "\uD83D\uDC72\uD83C\uDFFB", + [":man_with_chinese_cap_tone2:"] = "\uD83D\uDC72\uD83C\uDFFC", + [":man_with_chinese_cap_tone3:"] = "\uD83D\uDC72\uD83C\uDFFD", + [":man_with_chinese_cap_tone4:"] = "\uD83D\uDC72\uD83C\uDFFE", + [":man_with_chinese_cap_tone5:"] = "\uD83D\uDC72\uD83C\uDFFF", + [":man_with_gua_pi_mao:"] = "\uD83D\uDC72", + [":man_with_gua_pi_mao::skin-tone-1:"] = "\uD83D\uDC72\uD83C\uDFFB", + [":man_with_gua_pi_mao::skin-tone-2:"] = "\uD83D\uDC72\uD83C\uDFFC", + [":man_with_gua_pi_mao::skin-tone-3:"] = "\uD83D\uDC72\uD83C\uDFFD", + [":man_with_gua_pi_mao::skin-tone-4:"] = "\uD83D\uDC72\uD83C\uDFFE", + [":man_with_gua_pi_mao::skin-tone-5:"] = "\uD83D\uDC72\uD83C\uDFFF", + [":man_with_gua_pi_mao_tone1:"] = "\uD83D\uDC72\uD83C\uDFFB", + [":man_with_gua_pi_mao_tone2:"] = "\uD83D\uDC72\uD83C\uDFFC", + [":man_with_gua_pi_mao_tone3:"] = "\uD83D\uDC72\uD83C\uDFFD", + [":man_with_gua_pi_mao_tone4:"] = "\uD83D\uDC72\uD83C\uDFFE", + [":man_with_gua_pi_mao_tone5:"] = "\uD83D\uDC72\uD83C\uDFFF", + [":man_with_probing_cane:"] = "\uD83D\uDC68\u200D\uD83E\uDDAF", + [":man_with_probing_cane::skin-tone-1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDAF", + [":man_with_probing_cane::skin-tone-2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDAF", + [":man_with_probing_cane::skin-tone-3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDAF", + [":man_with_probing_cane::skin-tone-4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDAF", + [":man_with_probing_cane::skin-tone-5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDAF", + [":man_with_probing_cane_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDAF", + [":man_with_probing_cane_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDAF", + [":man_with_probing_cane_medium_dark_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDAF", + [":man_with_probing_cane_medium_light_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDAF", + [":man_with_probing_cane_medium_skin_tone:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDAF", + [":man_with_probing_cane_tone1:"] = "\uD83D\uDC68\uD83C\uDFFB\u200D\uD83E\uDDAF", + [":man_with_probing_cane_tone2:"] = "\uD83D\uDC68\uD83C\uDFFC\u200D\uD83E\uDDAF", + [":man_with_probing_cane_tone3:"] = "\uD83D\uDC68\uD83C\uDFFD\u200D\uD83E\uDDAF", + [":man_with_probing_cane_tone4:"] = "\uD83D\uDC68\uD83C\uDFFE\u200D\uD83E\uDDAF", + [":man_with_probing_cane_tone5:"] = "\uD83D\uDC68\uD83C\uDFFF\u200D\uD83E\uDDAF", + [":man_with_turban:"] = "\uD83D\uDC73", + [":man_with_turban::skin-tone-1:"] = "\uD83D\uDC73\uD83C\uDFFB", + [":man_with_turban::skin-tone-2:"] = "\uD83D\uDC73\uD83C\uDFFC", + [":man_with_turban::skin-tone-3:"] = "\uD83D\uDC73\uD83C\uDFFD", + [":man_with_turban::skin-tone-4:"] = "\uD83D\uDC73\uD83C\uDFFE", + [":man_with_turban::skin-tone-5:"] = "\uD83D\uDC73\uD83C\uDFFF", + [":man_with_turban_tone1:"] = "\uD83D\uDC73\uD83C\uDFFB", + [":man_with_turban_tone2:"] = "\uD83D\uDC73\uD83C\uDFFC", + [":man_with_turban_tone3:"] = "\uD83D\uDC73\uD83C\uDFFD", + [":man_with_turban_tone4:"] = "\uD83D\uDC73\uD83C\uDFFE", + [":man_with_turban_tone5:"] = "\uD83D\uDC73\uD83C\uDFFF", + [":man_zombie:"] = "\uD83E\uDDDF\u200D♂️", + [":mango:"] = "\uD83E\uDD6D", + [":mans_shoe:"] = "\uD83D\uDC5E", + [":mantlepiece_clock:"] = "\uD83D\uDD70️", + [":manual_wheelchair:"] = "\uD83E\uDDBD", + [":map:"] = "\uD83D\uDDFA️", + [":maple_leaf:"] = "\uD83C\uDF41", + [":martial_arts_uniform:"] = "\uD83E\uDD4B", + [":mask:"] = "\uD83D\uDE37", + [":massage:"] = "\uD83D\uDC86", + [":massage::skin-tone-1:"] = "\uD83D\uDC86\uD83C\uDFFB", + [":massage::skin-tone-2:"] = "\uD83D\uDC86\uD83C\uDFFC", + [":massage::skin-tone-3:"] = "\uD83D\uDC86\uD83C\uDFFD", + [":massage::skin-tone-4:"] = "\uD83D\uDC86\uD83C\uDFFE", + [":massage::skin-tone-5:"] = "\uD83D\uDC86\uD83C\uDFFF", + [":massage_tone1:"] = "\uD83D\uDC86\uD83C\uDFFB", + [":massage_tone2:"] = "\uD83D\uDC86\uD83C\uDFFC", + [":massage_tone3:"] = "\uD83D\uDC86\uD83C\uDFFD", + [":massage_tone4:"] = "\uD83D\uDC86\uD83C\uDFFE", + [":massage_tone5:"] = "\uD83D\uDC86\uD83C\uDFFF", + [":mate:"] = "\uD83E\uDDC9", + [":meat_on_bone:"] = "\uD83C\uDF56", + [":mechanical_arm:"] = "\uD83E\uDDBE", + [":mechanical_leg:"] = "\uD83E\uDDBF", + [":medal:"] = "\uD83C\uDFC5", + [":medical_symbol:"] = "⚕️", + [":mega:"] = "\uD83D\uDCE3", + [":melon:"] = "\uD83C\uDF48", + [":memo:"] = "\uD83D\uDCDD", + [":men_with_bunny_ears_partying:"] = "\uD83D\uDC6F\u200D♂️", + [":men_wrestling:"] = "\uD83E\uDD3C\u200D♂️", + [":menorah:"] = "\uD83D\uDD4E", + [":mens:"] = "\uD83D\uDEB9", + [":mermaid:"] = "\uD83E\uDDDC\u200D♀️", + [":mermaid::skin-tone-1:"] = "\uD83E\uDDDC\uD83C\uDFFB\u200D♀️", + [":mermaid::skin-tone-2:"] = "\uD83E\uDDDC\uD83C\uDFFC\u200D♀️", + [":mermaid::skin-tone-3:"] = "\uD83E\uDDDC\uD83C\uDFFD\u200D♀️", + [":mermaid::skin-tone-4:"] = "\uD83E\uDDDC\uD83C\uDFFE\u200D♀️", + [":mermaid::skin-tone-5:"] = "\uD83E\uDDDC\uD83C\uDFFF\u200D♀️", + [":mermaid_dark_skin_tone:"] = "\uD83E\uDDDC\uD83C\uDFFF\u200D♀️", + [":mermaid_light_skin_tone:"] = "\uD83E\uDDDC\uD83C\uDFFB\u200D♀️", + [":mermaid_medium_dark_skin_tone:"] = "\uD83E\uDDDC\uD83C\uDFFE\u200D♀️", + [":mermaid_medium_light_skin_tone:"] = "\uD83E\uDDDC\uD83C\uDFFC\u200D♀️", + [":mermaid_medium_skin_tone:"] = "\uD83E\uDDDC\uD83C\uDFFD\u200D♀️", + [":mermaid_tone1:"] = "\uD83E\uDDDC\uD83C\uDFFB\u200D♀️", + [":mermaid_tone2:"] = "\uD83E\uDDDC\uD83C\uDFFC\u200D♀️", + [":mermaid_tone3:"] = "\uD83E\uDDDC\uD83C\uDFFD\u200D♀️", + [":mermaid_tone4:"] = "\uD83E\uDDDC\uD83C\uDFFE\u200D♀️", + [":mermaid_tone5:"] = "\uD83E\uDDDC\uD83C\uDFFF\u200D♀️", + [":merman:"] = "\uD83E\uDDDC\u200D♂️", + [":merman::skin-tone-1:"] = "\uD83E\uDDDC\uD83C\uDFFB\u200D♂️", + [":merman::skin-tone-2:"] = "\uD83E\uDDDC\uD83C\uDFFC\u200D♂️", + [":merman::skin-tone-3:"] = "\uD83E\uDDDC\uD83C\uDFFD\u200D♂️", + [":merman::skin-tone-4:"] = "\uD83E\uDDDC\uD83C\uDFFE\u200D♂️", + [":merman::skin-tone-5:"] = "\uD83E\uDDDC\uD83C\uDFFF\u200D♂️", + [":merman_dark_skin_tone:"] = "\uD83E\uDDDC\uD83C\uDFFF\u200D♂️", + [":merman_light_skin_tone:"] = "\uD83E\uDDDC\uD83C\uDFFB\u200D♂️", + [":merman_medium_dark_skin_tone:"] = "\uD83E\uDDDC\uD83C\uDFFE\u200D♂️", + [":merman_medium_light_skin_tone:"] = "\uD83E\uDDDC\uD83C\uDFFC\u200D♂️", + [":merman_medium_skin_tone:"] = "\uD83E\uDDDC\uD83C\uDFFD\u200D♂️", + [":merman_tone1:"] = "\uD83E\uDDDC\uD83C\uDFFB\u200D♂️", + [":merman_tone2:"] = "\uD83E\uDDDC\uD83C\uDFFC\u200D♂️", + [":merman_tone3:"] = "\uD83E\uDDDC\uD83C\uDFFD\u200D♂️", + [":merman_tone4:"] = "\uD83E\uDDDC\uD83C\uDFFE\u200D♂️", + [":merman_tone5:"] = "\uD83E\uDDDC\uD83C\uDFFF\u200D♂️", + [":merperson:"] = "\uD83E\uDDDC", + [":merperson::skin-tone-1:"] = "\uD83E\uDDDC\uD83C\uDFFB", + [":merperson::skin-tone-2:"] = "\uD83E\uDDDC\uD83C\uDFFC", + [":merperson::skin-tone-3:"] = "\uD83E\uDDDC\uD83C\uDFFD", + [":merperson::skin-tone-4:"] = "\uD83E\uDDDC\uD83C\uDFFE", + [":merperson::skin-tone-5:"] = "\uD83E\uDDDC\uD83C\uDFFF", + [":merperson_dark_skin_tone:"] = "\uD83E\uDDDC\uD83C\uDFFF", + [":merperson_light_skin_tone:"] = "\uD83E\uDDDC\uD83C\uDFFB", + [":merperson_medium_dark_skin_tone:"] = "\uD83E\uDDDC\uD83C\uDFFE", + [":merperson_medium_light_skin_tone:"] = "\uD83E\uDDDC\uD83C\uDFFC", + [":merperson_medium_skin_tone:"] = "\uD83E\uDDDC\uD83C\uDFFD", + [":merperson_tone1:"] = "\uD83E\uDDDC\uD83C\uDFFB", + [":merperson_tone2:"] = "\uD83E\uDDDC\uD83C\uDFFC", + [":merperson_tone3:"] = "\uD83E\uDDDC\uD83C\uDFFD", + [":merperson_tone4:"] = "\uD83E\uDDDC\uD83C\uDFFE", + [":merperson_tone5:"] = "\uD83E\uDDDC\uD83C\uDFFF", + [":metal:"] = "\uD83E\uDD18", + [":metal::skin-tone-1:"] = "\uD83E\uDD18\uD83C\uDFFB", + [":metal::skin-tone-2:"] = "\uD83E\uDD18\uD83C\uDFFC", + [":metal::skin-tone-3:"] = "\uD83E\uDD18\uD83C\uDFFD", + [":metal::skin-tone-4:"] = "\uD83E\uDD18\uD83C\uDFFE", + [":metal::skin-tone-5:"] = "\uD83E\uDD18\uD83C\uDFFF", + [":metal_tone1:"] = "\uD83E\uDD18\uD83C\uDFFB", + [":metal_tone2:"] = "\uD83E\uDD18\uD83C\uDFFC", + [":metal_tone3:"] = "\uD83E\uDD18\uD83C\uDFFD", + [":metal_tone4:"] = "\uD83E\uDD18\uD83C\uDFFE", + [":metal_tone5:"] = "\uD83E\uDD18\uD83C\uDFFF", + [":metro:"] = "\uD83D\uDE87", + [":microbe:"] = "\uD83E\uDDA0", + [":microphone2:"] = "\uD83C\uDF99️", + [":microphone:"] = "\uD83C\uDFA4", + [":microscope:"] = "\uD83D\uDD2C", + [":middle_finger:"] = "\uD83D\uDD95", + [":middle_finger::skin-tone-1:"] = "\uD83D\uDD95\uD83C\uDFFB", + [":middle_finger::skin-tone-2:"] = "\uD83D\uDD95\uD83C\uDFFC", + [":middle_finger::skin-tone-3:"] = "\uD83D\uDD95\uD83C\uDFFD", + [":middle_finger::skin-tone-4:"] = "\uD83D\uDD95\uD83C\uDFFE", + [":middle_finger::skin-tone-5:"] = "\uD83D\uDD95\uD83C\uDFFF", + [":middle_finger_tone1:"] = "\uD83D\uDD95\uD83C\uDFFB", + [":middle_finger_tone2:"] = "\uD83D\uDD95\uD83C\uDFFC", + [":middle_finger_tone3:"] = "\uD83D\uDD95\uD83C\uDFFD", + [":middle_finger_tone4:"] = "\uD83D\uDD95\uD83C\uDFFE", + [":middle_finger_tone5:"] = "\uD83D\uDD95\uD83C\uDFFF", + [":military_medal:"] = "\uD83C\uDF96️", + [":milk:"] = "\uD83E\uDD5B", + [":milky_way:"] = "\uD83C\uDF0C", + [":minibus:"] = "\uD83D\uDE90", + [":minidisc:"] = "\uD83D\uDCBD", + [":mobile_phone_off:"] = "\uD83D\uDCF4", + [":money_mouth:"] = "\uD83E\uDD11", + [":money_mouth_face:"] = "\uD83E\uDD11", + [":money_with_wings:"] = "\uD83D\uDCB8", + [":moneybag:"] = "\uD83D\uDCB0", + [":monkey:"] = "\uD83D\uDC12", + [":monkey_face:"] = "\uD83D\uDC35", + [":monorail:"] = "\uD83D\uDE9D", + [":moon_cake:"] = "\uD83E\uDD6E", + [":mortar_board:"] = "\uD83C\uDF93", + [":mosque:"] = "\uD83D\uDD4C", + [":mosquito:"] = "\uD83E\uDD9F", + [":mother_christmas:"] = "\uD83E\uDD36", + [":mother_christmas::skin-tone-1:"] = "\uD83E\uDD36\uD83C\uDFFB", + [":mother_christmas::skin-tone-2:"] = "\uD83E\uDD36\uD83C\uDFFC", + [":mother_christmas::skin-tone-3:"] = "\uD83E\uDD36\uD83C\uDFFD", + [":mother_christmas::skin-tone-4:"] = "\uD83E\uDD36\uD83C\uDFFE", + [":mother_christmas::skin-tone-5:"] = "\uD83E\uDD36\uD83C\uDFFF", + [":mother_christmas_tone1:"] = "\uD83E\uDD36\uD83C\uDFFB", + [":mother_christmas_tone2:"] = "\uD83E\uDD36\uD83C\uDFFC", + [":mother_christmas_tone3:"] = "\uD83E\uDD36\uD83C\uDFFD", + [":mother_christmas_tone4:"] = "\uD83E\uDD36\uD83C\uDFFE", + [":mother_christmas_tone5:"] = "\uD83E\uDD36\uD83C\uDFFF", + [":motor_scooter:"] = "\uD83D\uDEF5", + [":motorbike:"] = "\uD83D\uDEF5", + [":motorboat:"] = "\uD83D\uDEE5️", + [":motorcycle:"] = "\uD83C\uDFCD️", + [":motorized_wheelchair:"] = "\uD83E\uDDBC", + [":motorway:"] = "\uD83D\uDEE3️", + [":mount_fuji:"] = "\uD83D\uDDFB", + [":mountain:"] = "⛰️", + [":mountain_bicyclist:"] = "\uD83D\uDEB5", + [":mountain_bicyclist::skin-tone-1:"] = "\uD83D\uDEB5\uD83C\uDFFB", + [":mountain_bicyclist::skin-tone-2:"] = "\uD83D\uDEB5\uD83C\uDFFC", + [":mountain_bicyclist::skin-tone-3:"] = "\uD83D\uDEB5\uD83C\uDFFD", + [":mountain_bicyclist::skin-tone-4:"] = "\uD83D\uDEB5\uD83C\uDFFE", + [":mountain_bicyclist::skin-tone-5:"] = "\uD83D\uDEB5\uD83C\uDFFF", + [":mountain_bicyclist_tone1:"] = "\uD83D\uDEB5\uD83C\uDFFB", + [":mountain_bicyclist_tone2:"] = "\uD83D\uDEB5\uD83C\uDFFC", + [":mountain_bicyclist_tone3:"] = "\uD83D\uDEB5\uD83C\uDFFD", + [":mountain_bicyclist_tone4:"] = "\uD83D\uDEB5\uD83C\uDFFE", + [":mountain_bicyclist_tone5:"] = "\uD83D\uDEB5\uD83C\uDFFF", + [":mountain_cableway:"] = "\uD83D\uDEA0", + [":mountain_railway:"] = "\uD83D\uDE9E", + [":mountain_snow:"] = "\uD83C\uDFD4️", + [":mouse2:"] = "\uD83D\uDC01", + [":mouse:"] = "\uD83D\uDC2D", + [":mouse_three_button:"] = "\uD83D\uDDB1️", + [":movie_camera:"] = "\uD83C\uDFA5", + [":moyai:"] = "\uD83D\uDDFF", + [":mrs_claus:"] = "\uD83E\uDD36", + [":mrs_claus::skin-tone-1:"] = "\uD83E\uDD36\uD83C\uDFFB", + [":mrs_claus::skin-tone-2:"] = "\uD83E\uDD36\uD83C\uDFFC", + [":mrs_claus::skin-tone-3:"] = "\uD83E\uDD36\uD83C\uDFFD", + [":mrs_claus::skin-tone-4:"] = "\uD83E\uDD36\uD83C\uDFFE", + [":mrs_claus::skin-tone-5:"] = "\uD83E\uDD36\uD83C\uDFFF", + [":mrs_claus_tone1:"] = "\uD83E\uDD36\uD83C\uDFFB", + [":mrs_claus_tone2:"] = "\uD83E\uDD36\uD83C\uDFFC", + [":mrs_claus_tone3:"] = "\uD83E\uDD36\uD83C\uDFFD", + [":mrs_claus_tone4:"] = "\uD83E\uDD36\uD83C\uDFFE", + [":mrs_claus_tone5:"] = "\uD83E\uDD36\uD83C\uDFFF", + [":muscle:"] = "\uD83D\uDCAA", + [":muscle::skin-tone-1:"] = "\uD83D\uDCAA\uD83C\uDFFB", + [":muscle::skin-tone-2:"] = "\uD83D\uDCAA\uD83C\uDFFC", + [":muscle::skin-tone-3:"] = "\uD83D\uDCAA\uD83C\uDFFD", + [":muscle::skin-tone-4:"] = "\uD83D\uDCAA\uD83C\uDFFE", + [":muscle::skin-tone-5:"] = "\uD83D\uDCAA\uD83C\uDFFF", + [":muscle_tone1:"] = "\uD83D\uDCAA\uD83C\uDFFB", + [":muscle_tone2:"] = "\uD83D\uDCAA\uD83C\uDFFC", + [":muscle_tone3:"] = "\uD83D\uDCAA\uD83C\uDFFD", + [":muscle_tone4:"] = "\uD83D\uDCAA\uD83C\uDFFE", + [":muscle_tone5:"] = "\uD83D\uDCAA\uD83C\uDFFF", + [":mushroom:"] = "\uD83C\uDF44", + [":musical_keyboard:"] = "\uD83C\uDFB9", + [":musical_note:"] = "\uD83C\uDFB5", + [":musical_score:"] = "\uD83C\uDFBC", + [":mute:"] = "\uD83D\uDD07", + [":nail_care:"] = "\uD83D\uDC85", + [":nail_care::skin-tone-1:"] = "\uD83D\uDC85\uD83C\uDFFB", + [":nail_care::skin-tone-2:"] = "\uD83D\uDC85\uD83C\uDFFC", + [":nail_care::skin-tone-3:"] = "\uD83D\uDC85\uD83C\uDFFD", + [":nail_care::skin-tone-4:"] = "\uD83D\uDC85\uD83C\uDFFE", + [":nail_care::skin-tone-5:"] = "\uD83D\uDC85\uD83C\uDFFF", + [":nail_care_tone1:"] = "\uD83D\uDC85\uD83C\uDFFB", + [":nail_care_tone2:"] = "\uD83D\uDC85\uD83C\uDFFC", + [":nail_care_tone3:"] = "\uD83D\uDC85\uD83C\uDFFD", + [":nail_care_tone4:"] = "\uD83D\uDC85\uD83C\uDFFE", + [":nail_care_tone5:"] = "\uD83D\uDC85\uD83C\uDFFF", + [":name_badge:"] = "\uD83D\uDCDB", + [":national_park:"] = "\uD83C\uDFDE️", + [":nauseated_face:"] = "\uD83E\uDD22", + [":nazar_amulet:"] = "\uD83E\uDDFF", + [":necktie:"] = "\uD83D\uDC54", + [":negative_squared_cross_mark:"] = "❎", + [":nerd:"] = "\uD83E\uDD13", + [":nerd_face:"] = "\uD83E\uDD13", + [":neutral_face:"] = "\uD83D\uDE10", + [":new:"] = "\uD83C\uDD95", + [":new_moon:"] = "\uD83C\uDF11", + [":new_moon_with_face:"] = "\uD83C\uDF1A", + [":newspaper2:"] = "\uD83D\uDDDE️", + [":newspaper:"] = "\uD83D\uDCF0", + [":next_track:"] = "⏭️", + [":ng:"] = "\uD83C\uDD96", + [":night_with_stars:"] = "\uD83C\uDF03", + [":nine:"] = "9️⃣", + [":no_bell:"] = "\uD83D\uDD15", + [":no_bicycles:"] = "\uD83D\uDEB3", + [":no_entry:"] = "⛔", + [":no_entry_sign:"] = "\uD83D\uDEAB", + [":no_good:"] = "\uD83D\uDE45", + [":no_good::skin-tone-1:"] = "\uD83D\uDE45\uD83C\uDFFB", + [":no_good::skin-tone-2:"] = "\uD83D\uDE45\uD83C\uDFFC", + [":no_good::skin-tone-3:"] = "\uD83D\uDE45\uD83C\uDFFD", + [":no_good::skin-tone-4:"] = "\uD83D\uDE45\uD83C\uDFFE", + [":no_good::skin-tone-5:"] = "\uD83D\uDE45\uD83C\uDFFF", + [":no_good_tone1:"] = "\uD83D\uDE45\uD83C\uDFFB", + [":no_good_tone2:"] = "\uD83D\uDE45\uD83C\uDFFC", + [":no_good_tone3:"] = "\uD83D\uDE45\uD83C\uDFFD", + [":no_good_tone4:"] = "\uD83D\uDE45\uD83C\uDFFE", + [":no_good_tone5:"] = "\uD83D\uDE45\uD83C\uDFFF", + [":no_mobile_phones:"] = "\uD83D\uDCF5", + [":no_mouth:"] = "\uD83D\uDE36", + [":no_pedestrians:"] = "\uD83D\uDEB7", + [":no_smoking:"] = "\uD83D\uDEAD", + [":non_potable_water:"] = "\uD83D\uDEB1", + [":nose:"] = "\uD83D\uDC43", + [":nose::skin-tone-1:"] = "\uD83D\uDC43\uD83C\uDFFB", + [":nose::skin-tone-2:"] = "\uD83D\uDC43\uD83C\uDFFC", + [":nose::skin-tone-3:"] = "\uD83D\uDC43\uD83C\uDFFD", + [":nose::skin-tone-4:"] = "\uD83D\uDC43\uD83C\uDFFE", + [":nose::skin-tone-5:"] = "\uD83D\uDC43\uD83C\uDFFF", + [":nose_tone1:"] = "\uD83D\uDC43\uD83C\uDFFB", + [":nose_tone2:"] = "\uD83D\uDC43\uD83C\uDFFC", + [":nose_tone3:"] = "\uD83D\uDC43\uD83C\uDFFD", + [":nose_tone4:"] = "\uD83D\uDC43\uD83C\uDFFE", + [":nose_tone5:"] = "\uD83D\uDC43\uD83C\uDFFF", + [":notebook:"] = "\uD83D\uDCD3", + [":notebook_with_decorative_cover:"] = "\uD83D\uDCD4", + [":notepad_spiral:"] = "\uD83D\uDDD2️", + [":notes:"] = "\uD83C\uDFB6", + [":nut_and_bolt:"] = "\uD83D\uDD29", + [":o"] = "\uD83D\uDE2E", + [":o2:"] = "\uD83C\uDD7E️", + [":o:"] = "⭕", + [":ocean:"] = "\uD83C\uDF0A", + [":octagonal_sign:"] = "\uD83D\uDED1", + [":octopus:"] = "\uD83D\uDC19", + [":oden:"] = "\uD83C\uDF62", + [":office:"] = "\uD83C\uDFE2", + [":oil:"] = "\uD83D\uDEE2️", + [":oil_drum:"] = "\uD83D\uDEE2️", + [":ok:"] = "\uD83C\uDD97", + [":ok_hand:"] = "\uD83D\uDC4C", + [":ok_hand::skin-tone-1:"] = "\uD83D\uDC4C\uD83C\uDFFB", + [":ok_hand::skin-tone-2:"] = "\uD83D\uDC4C\uD83C\uDFFC", + [":ok_hand::skin-tone-3:"] = "\uD83D\uDC4C\uD83C\uDFFD", + [":ok_hand::skin-tone-4:"] = "\uD83D\uDC4C\uD83C\uDFFE", + [":ok_hand::skin-tone-5:"] = "\uD83D\uDC4C\uD83C\uDFFF", + [":ok_hand_tone1:"] = "\uD83D\uDC4C\uD83C\uDFFB", + [":ok_hand_tone2:"] = "\uD83D\uDC4C\uD83C\uDFFC", + [":ok_hand_tone3:"] = "\uD83D\uDC4C\uD83C\uDFFD", + [":ok_hand_tone4:"] = "\uD83D\uDC4C\uD83C\uDFFE", + [":ok_hand_tone5:"] = "\uD83D\uDC4C\uD83C\uDFFF", + [":ok_woman:"] = "\uD83D\uDE46", + [":ok_woman::skin-tone-1:"] = "\uD83D\uDE46\uD83C\uDFFB", + [":ok_woman::skin-tone-2:"] = "\uD83D\uDE46\uD83C\uDFFC", + [":ok_woman::skin-tone-3:"] = "\uD83D\uDE46\uD83C\uDFFD", + [":ok_woman::skin-tone-4:"] = "\uD83D\uDE46\uD83C\uDFFE", + [":ok_woman::skin-tone-5:"] = "\uD83D\uDE46\uD83C\uDFFF", + [":ok_woman_tone1:"] = "\uD83D\uDE46\uD83C\uDFFB", + [":ok_woman_tone2:"] = "\uD83D\uDE46\uD83C\uDFFC", + [":ok_woman_tone3:"] = "\uD83D\uDE46\uD83C\uDFFD", + [":ok_woman_tone4:"] = "\uD83D\uDE46\uD83C\uDFFE", + [":ok_woman_tone5:"] = "\uD83D\uDE46\uD83C\uDFFF", + [":old_key:"] = "\uD83D\uDDDD️", + [":older_adult:"] = "\uD83E\uDDD3", + [":older_adult::skin-tone-1:"] = "\uD83E\uDDD3\uD83C\uDFFB", + [":older_adult::skin-tone-2:"] = "\uD83E\uDDD3\uD83C\uDFFC", + [":older_adult::skin-tone-3:"] = "\uD83E\uDDD3\uD83C\uDFFD", + [":older_adult::skin-tone-4:"] = "\uD83E\uDDD3\uD83C\uDFFE", + [":older_adult::skin-tone-5:"] = "\uD83E\uDDD3\uD83C\uDFFF", + [":older_adult_dark_skin_tone:"] = "\uD83E\uDDD3\uD83C\uDFFF", + [":older_adult_light_skin_tone:"] = "\uD83E\uDDD3\uD83C\uDFFB", + [":older_adult_medium_dark_skin_tone:"] = "\uD83E\uDDD3\uD83C\uDFFE", + [":older_adult_medium_light_skin_tone:"] = "\uD83E\uDDD3\uD83C\uDFFC", + [":older_adult_medium_skin_tone:"] = "\uD83E\uDDD3\uD83C\uDFFD", + [":older_adult_tone1:"] = "\uD83E\uDDD3\uD83C\uDFFB", + [":older_adult_tone2:"] = "\uD83E\uDDD3\uD83C\uDFFC", + [":older_adult_tone3:"] = "\uD83E\uDDD3\uD83C\uDFFD", + [":older_adult_tone4:"] = "\uD83E\uDDD3\uD83C\uDFFE", + [":older_adult_tone5:"] = "\uD83E\uDDD3\uD83C\uDFFF", + [":older_man:"] = "\uD83D\uDC74", + [":older_man::skin-tone-1:"] = "\uD83D\uDC74\uD83C\uDFFB", + [":older_man::skin-tone-2:"] = "\uD83D\uDC74\uD83C\uDFFC", + [":older_man::skin-tone-3:"] = "\uD83D\uDC74\uD83C\uDFFD", + [":older_man::skin-tone-4:"] = "\uD83D\uDC74\uD83C\uDFFE", + [":older_man::skin-tone-5:"] = "\uD83D\uDC74\uD83C\uDFFF", + [":older_man_tone1:"] = "\uD83D\uDC74\uD83C\uDFFB", + [":older_man_tone2:"] = "\uD83D\uDC74\uD83C\uDFFC", + [":older_man_tone3:"] = "\uD83D\uDC74\uD83C\uDFFD", + [":older_man_tone4:"] = "\uD83D\uDC74\uD83C\uDFFE", + [":older_man_tone5:"] = "\uD83D\uDC74\uD83C\uDFFF", + [":older_woman:"] = "\uD83D\uDC75", + [":older_woman::skin-tone-1:"] = "\uD83D\uDC75\uD83C\uDFFB", + [":older_woman::skin-tone-2:"] = "\uD83D\uDC75\uD83C\uDFFC", + [":older_woman::skin-tone-3:"] = "\uD83D\uDC75\uD83C\uDFFD", + [":older_woman::skin-tone-4:"] = "\uD83D\uDC75\uD83C\uDFFE", + [":older_woman::skin-tone-5:"] = "\uD83D\uDC75\uD83C\uDFFF", + [":older_woman_tone1:"] = "\uD83D\uDC75\uD83C\uDFFB", + [":older_woman_tone2:"] = "\uD83D\uDC75\uD83C\uDFFC", + [":older_woman_tone3:"] = "\uD83D\uDC75\uD83C\uDFFD", + [":older_woman_tone4:"] = "\uD83D\uDC75\uD83C\uDFFE", + [":older_woman_tone5:"] = "\uD83D\uDC75\uD83C\uDFFF", + [":om_symbol:"] = "\uD83D\uDD49️", + [":on:"] = "\uD83D\uDD1B", + [":oncoming_automobile:"] = "\uD83D\uDE98", + [":oncoming_bus:"] = "\uD83D\uDE8D", + [":oncoming_police_car:"] = "\uD83D\uDE94", + [":oncoming_taxi:"] = "\uD83D\uDE96", + [":one:"] = "1️⃣", + [":one_piece_swimsuit:"] = "\uD83E\uDE71", + [":onion:"] = "\uD83E\uDDC5", + [":open_file_folder:"] = "\uD83D\uDCC2", + [":open_hands:"] = "\uD83D\uDC50", + [":open_hands::skin-tone-1:"] = "\uD83D\uDC50\uD83C\uDFFB", + [":open_hands::skin-tone-2:"] = "\uD83D\uDC50\uD83C\uDFFC", + [":open_hands::skin-tone-3:"] = "\uD83D\uDC50\uD83C\uDFFD", + [":open_hands::skin-tone-4:"] = "\uD83D\uDC50\uD83C\uDFFE", + [":open_hands::skin-tone-5:"] = "\uD83D\uDC50\uD83C\uDFFF", + [":open_hands_tone1:"] = "\uD83D\uDC50\uD83C\uDFFB", + [":open_hands_tone2:"] = "\uD83D\uDC50\uD83C\uDFFC", + [":open_hands_tone3:"] = "\uD83D\uDC50\uD83C\uDFFD", + [":open_hands_tone4:"] = "\uD83D\uDC50\uD83C\uDFFE", + [":open_hands_tone5:"] = "\uD83D\uDC50\uD83C\uDFFF", + [":open_mouth:"] = "\uD83D\uDE2E", + [":ophiuchus:"] = "⛎", + [":orange_book:"] = "\uD83D\uDCD9", + [":orange_circle:"] = "\uD83D\uDFE0", + [":orange_heart:"] = "\uD83E\uDDE1", + [":orange_square:"] = "\uD83D\uDFE7", + [":orangutan:"] = "\uD83E\uDDA7", + [":orthodox_cross:"] = "☦️", + [":otter:"] = "\uD83E\uDDA6", + [":outbox_tray:"] = "\uD83D\uDCE4", + [":owl:"] = "\uD83E\uDD89", + [":ox:"] = "\uD83D\uDC02", + [":oyster:"] = "\uD83E\uDDAA", + [":package:"] = "\uD83D\uDCE6", + [":paella:"] = "\uD83E\uDD58", + [":page_facing_up:"] = "\uD83D\uDCC4", + [":page_with_curl:"] = "\uD83D\uDCC3", + [":pager:"] = "\uD83D\uDCDF", + [":paintbrush:"] = "\uD83D\uDD8C️", + [":palm_tree:"] = "\uD83C\uDF34", + [":palms_up_together:"] = "\uD83E\uDD32", + [":palms_up_together::skin-tone-1:"] = "\uD83E\uDD32\uD83C\uDFFB", + [":palms_up_together::skin-tone-2:"] = "\uD83E\uDD32\uD83C\uDFFC", + [":palms_up_together::skin-tone-3:"] = "\uD83E\uDD32\uD83C\uDFFD", + [":palms_up_together::skin-tone-4:"] = "\uD83E\uDD32\uD83C\uDFFE", + [":palms_up_together::skin-tone-5:"] = "\uD83E\uDD32\uD83C\uDFFF", + [":palms_up_together_dark_skin_tone:"] = "\uD83E\uDD32\uD83C\uDFFF", + [":palms_up_together_light_skin_tone:"] = "\uD83E\uDD32\uD83C\uDFFB", + [":palms_up_together_medium_dark_skin_tone:"] = "\uD83E\uDD32\uD83C\uDFFE", + [":palms_up_together_medium_light_skin_tone:"] = "\uD83E\uDD32\uD83C\uDFFC", + [":palms_up_together_medium_skin_tone:"] = "\uD83E\uDD32\uD83C\uDFFD", + [":palms_up_together_tone1:"] = "\uD83E\uDD32\uD83C\uDFFB", + [":palms_up_together_tone2:"] = "\uD83E\uDD32\uD83C\uDFFC", + [":palms_up_together_tone3:"] = "\uD83E\uDD32\uD83C\uDFFD", + [":palms_up_together_tone4:"] = "\uD83E\uDD32\uD83C\uDFFE", + [":palms_up_together_tone5:"] = "\uD83E\uDD32\uD83C\uDFFF", + [":pancakes:"] = "\uD83E\uDD5E", + [":panda_face:"] = "\uD83D\uDC3C", + [":paperclip:"] = "\uD83D\uDCCE", + [":paperclips:"] = "\uD83D\uDD87️", + [":parachute:"] = "\uD83E\uDE82", + [":park:"] = "\uD83C\uDFDE️", + [":parking:"] = "\uD83C\uDD7F️", + [":parrot:"] = "\uD83E\uDD9C", + [":part_alternation_mark:"] = "〽️", + [":partly_sunny:"] = "⛅", + [":partying_face:"] = "\uD83E\uDD73", + [":passenger_ship:"] = "\uD83D\uDEF3️", + [":passport_control:"] = "\uD83D\uDEC2", + [":pause_button:"] = "⏸️", + [":paw_prints:"] = "\uD83D\uDC3E", + [":peace:"] = "☮️", + [":peace_symbol:"] = "☮️", + [":peach:"] = "\uD83C\uDF51", + [":peacock:"] = "\uD83E\uDD9A", + [":peanuts:"] = "\uD83E\uDD5C", + [":pear:"] = "\uD83C\uDF50", + [":pen_ballpoint:"] = "\uD83D\uDD8A️", + [":pen_fountain:"] = "\uD83D\uDD8B️", + [":pencil2:"] = "✏️", + [":pencil:"] = "\uD83D\uDCDD", + [":penguin:"] = "\uD83D\uDC27", + [":pensive:"] = "\uD83D\uDE14", + [":people_holding_hands:"] = "\uD83E\uDDD1\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1", + [":people_with_bunny_ears_partying:"] = "\uD83D\uDC6F", + [":people_wrestling:"] = "\uD83E\uDD3C", + [":performing_arts:"] = "\uD83C\uDFAD", + [":persevere:"] = "\uD83D\uDE23", + [":person_biking:"] = "\uD83D\uDEB4", + [":person_biking::skin-tone-1:"] = "\uD83D\uDEB4\uD83C\uDFFB", + [":person_biking::skin-tone-2:"] = "\uD83D\uDEB4\uD83C\uDFFC", + [":person_biking::skin-tone-3:"] = "\uD83D\uDEB4\uD83C\uDFFD", + [":person_biking::skin-tone-4:"] = "\uD83D\uDEB4\uD83C\uDFFE", + [":person_biking::skin-tone-5:"] = "\uD83D\uDEB4\uD83C\uDFFF", + [":person_biking_tone1:"] = "\uD83D\uDEB4\uD83C\uDFFB", + [":person_biking_tone2:"] = "\uD83D\uDEB4\uD83C\uDFFC", + [":person_biking_tone3:"] = "\uD83D\uDEB4\uD83C\uDFFD", + [":person_biking_tone4:"] = "\uD83D\uDEB4\uD83C\uDFFE", + [":person_biking_tone5:"] = "\uD83D\uDEB4\uD83C\uDFFF", + [":person_bouncing_ball:"] = "⛹️", + [":person_bouncing_ball::skin-tone-1:"] = "⛹\uD83C\uDFFB", + [":person_bouncing_ball::skin-tone-2:"] = "⛹\uD83C\uDFFC", + [":person_bouncing_ball::skin-tone-3:"] = "⛹\uD83C\uDFFD", + [":person_bouncing_ball::skin-tone-4:"] = "⛹\uD83C\uDFFE", + [":person_bouncing_ball::skin-tone-5:"] = "⛹\uD83C\uDFFF", + [":person_bouncing_ball_tone1:"] = "⛹\uD83C\uDFFB", + [":person_bouncing_ball_tone2:"] = "⛹\uD83C\uDFFC", + [":person_bouncing_ball_tone3:"] = "⛹\uD83C\uDFFD", + [":person_bouncing_ball_tone4:"] = "⛹\uD83C\uDFFE", + [":person_bouncing_ball_tone5:"] = "⛹\uD83C\uDFFF", + [":person_bowing:"] = "\uD83D\uDE47", + [":person_bowing::skin-tone-1:"] = "\uD83D\uDE47\uD83C\uDFFB", + [":person_bowing::skin-tone-2:"] = "\uD83D\uDE47\uD83C\uDFFC", + [":person_bowing::skin-tone-3:"] = "\uD83D\uDE47\uD83C\uDFFD", + [":person_bowing::skin-tone-4:"] = "\uD83D\uDE47\uD83C\uDFFE", + [":person_bowing::skin-tone-5:"] = "\uD83D\uDE47\uD83C\uDFFF", + [":person_bowing_tone1:"] = "\uD83D\uDE47\uD83C\uDFFB", + [":person_bowing_tone2:"] = "\uD83D\uDE47\uD83C\uDFFC", + [":person_bowing_tone3:"] = "\uD83D\uDE47\uD83C\uDFFD", + [":person_bowing_tone4:"] = "\uD83D\uDE47\uD83C\uDFFE", + [":person_bowing_tone5:"] = "\uD83D\uDE47\uD83C\uDFFF", + [":person_climbing:"] = "\uD83E\uDDD7", + [":person_climbing::skin-tone-1:"] = "\uD83E\uDDD7\uD83C\uDFFB", + [":person_climbing::skin-tone-2:"] = "\uD83E\uDDD7\uD83C\uDFFC", + [":person_climbing::skin-tone-3:"] = "\uD83E\uDDD7\uD83C\uDFFD", + [":person_climbing::skin-tone-4:"] = "\uD83E\uDDD7\uD83C\uDFFE", + [":person_climbing::skin-tone-5:"] = "\uD83E\uDDD7\uD83C\uDFFF", + [":person_climbing_dark_skin_tone:"] = "\uD83E\uDDD7\uD83C\uDFFF", + [":person_climbing_light_skin_tone:"] = "\uD83E\uDDD7\uD83C\uDFFB", + [":person_climbing_medium_dark_skin_tone:"] = "\uD83E\uDDD7\uD83C\uDFFE", + [":person_climbing_medium_light_skin_tone:"] = "\uD83E\uDDD7\uD83C\uDFFC", + [":person_climbing_medium_skin_tone:"] = "\uD83E\uDDD7\uD83C\uDFFD", + [":person_climbing_tone1:"] = "\uD83E\uDDD7\uD83C\uDFFB", + [":person_climbing_tone2:"] = "\uD83E\uDDD7\uD83C\uDFFC", + [":person_climbing_tone3:"] = "\uD83E\uDDD7\uD83C\uDFFD", + [":person_climbing_tone4:"] = "\uD83E\uDDD7\uD83C\uDFFE", + [":person_climbing_tone5:"] = "\uD83E\uDDD7\uD83C\uDFFF", + [":person_doing_cartwheel:"] = "\uD83E\uDD38", + [":person_doing_cartwheel::skin-tone-1:"] = "\uD83E\uDD38\uD83C\uDFFB", + [":person_doing_cartwheel::skin-tone-2:"] = "\uD83E\uDD38\uD83C\uDFFC", + [":person_doing_cartwheel::skin-tone-3:"] = "\uD83E\uDD38\uD83C\uDFFD", + [":person_doing_cartwheel::skin-tone-4:"] = "\uD83E\uDD38\uD83C\uDFFE", + [":person_doing_cartwheel::skin-tone-5:"] = "\uD83E\uDD38\uD83C\uDFFF", + [":person_doing_cartwheel_tone1:"] = "\uD83E\uDD38\uD83C\uDFFB", + [":person_doing_cartwheel_tone2:"] = "\uD83E\uDD38\uD83C\uDFFC", + [":person_doing_cartwheel_tone3:"] = "\uD83E\uDD38\uD83C\uDFFD", + [":person_doing_cartwheel_tone4:"] = "\uD83E\uDD38\uD83C\uDFFE", + [":person_doing_cartwheel_tone5:"] = "\uD83E\uDD38\uD83C\uDFFF", + [":person_facepalming:"] = "\uD83E\uDD26", + [":person_facepalming::skin-tone-1:"] = "\uD83E\uDD26\uD83C\uDFFB", + [":person_facepalming::skin-tone-2:"] = "\uD83E\uDD26\uD83C\uDFFC", + [":person_facepalming::skin-tone-3:"] = "\uD83E\uDD26\uD83C\uDFFD", + [":person_facepalming::skin-tone-4:"] = "\uD83E\uDD26\uD83C\uDFFE", + [":person_facepalming::skin-tone-5:"] = "\uD83E\uDD26\uD83C\uDFFF", + [":person_facepalming_tone1:"] = "\uD83E\uDD26\uD83C\uDFFB", + [":person_facepalming_tone2:"] = "\uD83E\uDD26\uD83C\uDFFC", + [":person_facepalming_tone3:"] = "\uD83E\uDD26\uD83C\uDFFD", + [":person_facepalming_tone4:"] = "\uD83E\uDD26\uD83C\uDFFE", + [":person_facepalming_tone5:"] = "\uD83E\uDD26\uD83C\uDFFF", + [":person_fencing:"] = "\uD83E\uDD3A", + [":person_frowning:"] = "\uD83D\uDE4D", + [":person_frowning::skin-tone-1:"] = "\uD83D\uDE4D\uD83C\uDFFB", + [":person_frowning::skin-tone-2:"] = "\uD83D\uDE4D\uD83C\uDFFC", + [":person_frowning::skin-tone-3:"] = "\uD83D\uDE4D\uD83C\uDFFD", + [":person_frowning::skin-tone-4:"] = "\uD83D\uDE4D\uD83C\uDFFE", + [":person_frowning::skin-tone-5:"] = "\uD83D\uDE4D\uD83C\uDFFF", + [":person_frowning_tone1:"] = "\uD83D\uDE4D\uD83C\uDFFB", + [":person_frowning_tone2:"] = "\uD83D\uDE4D\uD83C\uDFFC", + [":person_frowning_tone3:"] = "\uD83D\uDE4D\uD83C\uDFFD", + [":person_frowning_tone4:"] = "\uD83D\uDE4D\uD83C\uDFFE", + [":person_frowning_tone5:"] = "\uD83D\uDE4D\uD83C\uDFFF", + [":person_gesturing_no:"] = "\uD83D\uDE45", + [":person_gesturing_no::skin-tone-1:"] = "\uD83D\uDE45\uD83C\uDFFB", + [":person_gesturing_no::skin-tone-2:"] = "\uD83D\uDE45\uD83C\uDFFC", + [":person_gesturing_no::skin-tone-3:"] = "\uD83D\uDE45\uD83C\uDFFD", + [":person_gesturing_no::skin-tone-4:"] = "\uD83D\uDE45\uD83C\uDFFE", + [":person_gesturing_no::skin-tone-5:"] = "\uD83D\uDE45\uD83C\uDFFF", + [":person_gesturing_no_tone1:"] = "\uD83D\uDE45\uD83C\uDFFB", + [":person_gesturing_no_tone2:"] = "\uD83D\uDE45\uD83C\uDFFC", + [":person_gesturing_no_tone3:"] = "\uD83D\uDE45\uD83C\uDFFD", + [":person_gesturing_no_tone4:"] = "\uD83D\uDE45\uD83C\uDFFE", + [":person_gesturing_no_tone5:"] = "\uD83D\uDE45\uD83C\uDFFF", + [":person_gesturing_ok:"] = "\uD83D\uDE46", + [":person_gesturing_ok::skin-tone-1:"] = "\uD83D\uDE46\uD83C\uDFFB", + [":person_gesturing_ok::skin-tone-2:"] = "\uD83D\uDE46\uD83C\uDFFC", + [":person_gesturing_ok::skin-tone-3:"] = "\uD83D\uDE46\uD83C\uDFFD", + [":person_gesturing_ok::skin-tone-4:"] = "\uD83D\uDE46\uD83C\uDFFE", + [":person_gesturing_ok::skin-tone-5:"] = "\uD83D\uDE46\uD83C\uDFFF", + [":person_gesturing_ok_tone1:"] = "\uD83D\uDE46\uD83C\uDFFB", + [":person_gesturing_ok_tone2:"] = "\uD83D\uDE46\uD83C\uDFFC", + [":person_gesturing_ok_tone3:"] = "\uD83D\uDE46\uD83C\uDFFD", + [":person_gesturing_ok_tone4:"] = "\uD83D\uDE46\uD83C\uDFFE", + [":person_gesturing_ok_tone5:"] = "\uD83D\uDE46\uD83C\uDFFF", + [":person_getting_haircut:"] = "\uD83D\uDC87", + [":person_getting_haircut::skin-tone-1:"] = "\uD83D\uDC87\uD83C\uDFFB", + [":person_getting_haircut::skin-tone-2:"] = "\uD83D\uDC87\uD83C\uDFFC", + [":person_getting_haircut::skin-tone-3:"] = "\uD83D\uDC87\uD83C\uDFFD", + [":person_getting_haircut::skin-tone-4:"] = "\uD83D\uDC87\uD83C\uDFFE", + [":person_getting_haircut::skin-tone-5:"] = "\uD83D\uDC87\uD83C\uDFFF", + [":person_getting_haircut_tone1:"] = "\uD83D\uDC87\uD83C\uDFFB", + [":person_getting_haircut_tone2:"] = "\uD83D\uDC87\uD83C\uDFFC", + [":person_getting_haircut_tone3:"] = "\uD83D\uDC87\uD83C\uDFFD", + [":person_getting_haircut_tone4:"] = "\uD83D\uDC87\uD83C\uDFFE", + [":person_getting_haircut_tone5:"] = "\uD83D\uDC87\uD83C\uDFFF", + [":person_getting_massage:"] = "\uD83D\uDC86", + [":person_getting_massage::skin-tone-1:"] = "\uD83D\uDC86\uD83C\uDFFB", + [":person_getting_massage::skin-tone-2:"] = "\uD83D\uDC86\uD83C\uDFFC", + [":person_getting_massage::skin-tone-3:"] = "\uD83D\uDC86\uD83C\uDFFD", + [":person_getting_massage::skin-tone-4:"] = "\uD83D\uDC86\uD83C\uDFFE", + [":person_getting_massage::skin-tone-5:"] = "\uD83D\uDC86\uD83C\uDFFF", + [":person_getting_massage_tone1:"] = "\uD83D\uDC86\uD83C\uDFFB", + [":person_getting_massage_tone2:"] = "\uD83D\uDC86\uD83C\uDFFC", + [":person_getting_massage_tone3:"] = "\uD83D\uDC86\uD83C\uDFFD", + [":person_getting_massage_tone4:"] = "\uD83D\uDC86\uD83C\uDFFE", + [":person_getting_massage_tone5:"] = "\uD83D\uDC86\uD83C\uDFFF", + [":person_golfing:"] = "\uD83C\uDFCC️", + [":person_golfing::skin-tone-1:"] = "\uD83C\uDFCC\uD83C\uDFFB", + [":person_golfing::skin-tone-2:"] = "\uD83C\uDFCC\uD83C\uDFFC", + [":person_golfing::skin-tone-3:"] = "\uD83C\uDFCC\uD83C\uDFFD", + [":person_golfing::skin-tone-4:"] = "\uD83C\uDFCC\uD83C\uDFFE", + [":person_golfing::skin-tone-5:"] = "\uD83C\uDFCC\uD83C\uDFFF", + [":person_golfing_dark_skin_tone:"] = "\uD83C\uDFCC\uD83C\uDFFF", + [":person_golfing_light_skin_tone:"] = "\uD83C\uDFCC\uD83C\uDFFB", + [":person_golfing_medium_dark_skin_tone:"] = "\uD83C\uDFCC\uD83C\uDFFE", + [":person_golfing_medium_light_skin_tone:"] = "\uD83C\uDFCC\uD83C\uDFFC", + [":person_golfing_medium_skin_tone:"] = "\uD83C\uDFCC\uD83C\uDFFD", + [":person_golfing_tone1:"] = "\uD83C\uDFCC\uD83C\uDFFB", + [":person_golfing_tone2:"] = "\uD83C\uDFCC\uD83C\uDFFC", + [":person_golfing_tone3:"] = "\uD83C\uDFCC\uD83C\uDFFD", + [":person_golfing_tone4:"] = "\uD83C\uDFCC\uD83C\uDFFE", + [":person_golfing_tone5:"] = "\uD83C\uDFCC\uD83C\uDFFF", + [":person_in_bed_dark_skin_tone:"] = "\uD83D\uDECC\uD83C\uDFFF", + [":person_in_bed_light_skin_tone:"] = "\uD83D\uDECC\uD83C\uDFFB", + [":person_in_bed_medium_dark_skin_tone:"] = "\uD83D\uDECC\uD83C\uDFFE", + [":person_in_bed_medium_light_skin_tone:"] = "\uD83D\uDECC\uD83C\uDFFC", + [":person_in_bed_medium_skin_tone:"] = "\uD83D\uDECC\uD83C\uDFFD", + [":person_in_bed_tone1:"] = "\uD83D\uDECC\uD83C\uDFFB", + [":person_in_bed_tone2:"] = "\uD83D\uDECC\uD83C\uDFFC", + [":person_in_bed_tone3:"] = "\uD83D\uDECC\uD83C\uDFFD", + [":person_in_bed_tone4:"] = "\uD83D\uDECC\uD83C\uDFFE", + [":person_in_bed_tone5:"] = "\uD83D\uDECC\uD83C\uDFFF", + [":person_in_lotus_position:"] = "\uD83E\uDDD8", + [":person_in_lotus_position::skin-tone-1:"] = "\uD83E\uDDD8\uD83C\uDFFB", + [":person_in_lotus_position::skin-tone-2:"] = "\uD83E\uDDD8\uD83C\uDFFC", + [":person_in_lotus_position::skin-tone-3:"] = "\uD83E\uDDD8\uD83C\uDFFD", + [":person_in_lotus_position::skin-tone-4:"] = "\uD83E\uDDD8\uD83C\uDFFE", + [":person_in_lotus_position::skin-tone-5:"] = "\uD83E\uDDD8\uD83C\uDFFF", + [":person_in_lotus_position_dark_skin_tone:"] = "\uD83E\uDDD8\uD83C\uDFFF", + [":person_in_lotus_position_light_skin_tone:"] = "\uD83E\uDDD8\uD83C\uDFFB", + [":person_in_lotus_position_medium_dark_skin_tone:"] = "\uD83E\uDDD8\uD83C\uDFFE", + [":person_in_lotus_position_medium_light_skin_tone:"] = "\uD83E\uDDD8\uD83C\uDFFC", + [":person_in_lotus_position_medium_skin_tone:"] = "\uD83E\uDDD8\uD83C\uDFFD", + [":person_in_lotus_position_tone1:"] = "\uD83E\uDDD8\uD83C\uDFFB", + [":person_in_lotus_position_tone2:"] = "\uD83E\uDDD8\uD83C\uDFFC", + [":person_in_lotus_position_tone3:"] = "\uD83E\uDDD8\uD83C\uDFFD", + [":person_in_lotus_position_tone4:"] = "\uD83E\uDDD8\uD83C\uDFFE", + [":person_in_lotus_position_tone5:"] = "\uD83E\uDDD8\uD83C\uDFFF", + [":person_in_steamy_room:"] = "\uD83E\uDDD6", + [":person_in_steamy_room::skin-tone-1:"] = "\uD83E\uDDD6\uD83C\uDFFB", + [":person_in_steamy_room::skin-tone-2:"] = "\uD83E\uDDD6\uD83C\uDFFC", + [":person_in_steamy_room::skin-tone-3:"] = "\uD83E\uDDD6\uD83C\uDFFD", + [":person_in_steamy_room::skin-tone-4:"] = "\uD83E\uDDD6\uD83C\uDFFE", + [":person_in_steamy_room::skin-tone-5:"] = "\uD83E\uDDD6\uD83C\uDFFF", + [":person_in_steamy_room_dark_skin_tone:"] = "\uD83E\uDDD6\uD83C\uDFFF", + [":person_in_steamy_room_light_skin_tone:"] = "\uD83E\uDDD6\uD83C\uDFFB", + [":person_in_steamy_room_medium_dark_skin_tone:"] = "\uD83E\uDDD6\uD83C\uDFFE", + [":person_in_steamy_room_medium_light_skin_tone:"] = "\uD83E\uDDD6\uD83C\uDFFC", + [":person_in_steamy_room_medium_skin_tone:"] = "\uD83E\uDDD6\uD83C\uDFFD", + [":person_in_steamy_room_tone1:"] = "\uD83E\uDDD6\uD83C\uDFFB", + [":person_in_steamy_room_tone2:"] = "\uD83E\uDDD6\uD83C\uDFFC", + [":person_in_steamy_room_tone3:"] = "\uD83E\uDDD6\uD83C\uDFFD", + [":person_in_steamy_room_tone4:"] = "\uD83E\uDDD6\uD83C\uDFFE", + [":person_in_steamy_room_tone5:"] = "\uD83E\uDDD6\uD83C\uDFFF", + [":person_juggling:"] = "\uD83E\uDD39", + [":person_juggling::skin-tone-1:"] = "\uD83E\uDD39\uD83C\uDFFB", + [":person_juggling::skin-tone-2:"] = "\uD83E\uDD39\uD83C\uDFFC", + [":person_juggling::skin-tone-3:"] = "\uD83E\uDD39\uD83C\uDFFD", + [":person_juggling::skin-tone-4:"] = "\uD83E\uDD39\uD83C\uDFFE", + [":person_juggling::skin-tone-5:"] = "\uD83E\uDD39\uD83C\uDFFF", + [":person_juggling_tone1:"] = "\uD83E\uDD39\uD83C\uDFFB", + [":person_juggling_tone2:"] = "\uD83E\uDD39\uD83C\uDFFC", + [":person_juggling_tone3:"] = "\uD83E\uDD39\uD83C\uDFFD", + [":person_juggling_tone4:"] = "\uD83E\uDD39\uD83C\uDFFE", + [":person_juggling_tone5:"] = "\uD83E\uDD39\uD83C\uDFFF", + [":person_kneeling:"] = "\uD83E\uDDCE", + [":person_kneeling::skin-tone-1:"] = "\uD83E\uDDCE\uD83C\uDFFB", + [":person_kneeling::skin-tone-2:"] = "\uD83E\uDDCE\uD83C\uDFFC", + [":person_kneeling::skin-tone-3:"] = "\uD83E\uDDCE\uD83C\uDFFD", + [":person_kneeling::skin-tone-4:"] = "\uD83E\uDDCE\uD83C\uDFFE", + [":person_kneeling::skin-tone-5:"] = "\uD83E\uDDCE\uD83C\uDFFF", + [":person_kneeling_dark_skin_tone:"] = "\uD83E\uDDCE\uD83C\uDFFF", + [":person_kneeling_light_skin_tone:"] = "\uD83E\uDDCE\uD83C\uDFFB", + [":person_kneeling_medium_dark_skin_tone:"] = "\uD83E\uDDCE\uD83C\uDFFE", + [":person_kneeling_medium_light_skin_tone:"] = "\uD83E\uDDCE\uD83C\uDFFC", + [":person_kneeling_medium_skin_tone:"] = "\uD83E\uDDCE\uD83C\uDFFD", + [":person_kneeling_tone1:"] = "\uD83E\uDDCE\uD83C\uDFFB", + [":person_kneeling_tone2:"] = "\uD83E\uDDCE\uD83C\uDFFC", + [":person_kneeling_tone3:"] = "\uD83E\uDDCE\uD83C\uDFFD", + [":person_kneeling_tone4:"] = "\uD83E\uDDCE\uD83C\uDFFE", + [":person_kneeling_tone5:"] = "\uD83E\uDDCE\uD83C\uDFFF", + [":person_lifting_weights:"] = "\uD83C\uDFCB️", + [":person_lifting_weights::skin-tone-1:"] = "\uD83C\uDFCB\uD83C\uDFFB", + [":person_lifting_weights::skin-tone-2:"] = "\uD83C\uDFCB\uD83C\uDFFC", + [":person_lifting_weights::skin-tone-3:"] = "\uD83C\uDFCB\uD83C\uDFFD", + [":person_lifting_weights::skin-tone-4:"] = "\uD83C\uDFCB\uD83C\uDFFE", + [":person_lifting_weights::skin-tone-5:"] = "\uD83C\uDFCB\uD83C\uDFFF", + [":person_lifting_weights_tone1:"] = "\uD83C\uDFCB\uD83C\uDFFB", + [":person_lifting_weights_tone2:"] = "\uD83C\uDFCB\uD83C\uDFFC", + [":person_lifting_weights_tone3:"] = "\uD83C\uDFCB\uD83C\uDFFD", + [":person_lifting_weights_tone4:"] = "\uD83C\uDFCB\uD83C\uDFFE", + [":person_lifting_weights_tone5:"] = "\uD83C\uDFCB\uD83C\uDFFF", + [":person_mountain_biking:"] = "\uD83D\uDEB5", + [":person_mountain_biking::skin-tone-1:"] = "\uD83D\uDEB5\uD83C\uDFFB", + [":person_mountain_biking::skin-tone-2:"] = "\uD83D\uDEB5\uD83C\uDFFC", + [":person_mountain_biking::skin-tone-3:"] = "\uD83D\uDEB5\uD83C\uDFFD", + [":person_mountain_biking::skin-tone-4:"] = "\uD83D\uDEB5\uD83C\uDFFE", + [":person_mountain_biking::skin-tone-5:"] = "\uD83D\uDEB5\uD83C\uDFFF", + [":person_mountain_biking_tone1:"] = "\uD83D\uDEB5\uD83C\uDFFB", + [":person_mountain_biking_tone2:"] = "\uD83D\uDEB5\uD83C\uDFFC", + [":person_mountain_biking_tone3:"] = "\uD83D\uDEB5\uD83C\uDFFD", + [":person_mountain_biking_tone4:"] = "\uD83D\uDEB5\uD83C\uDFFE", + [":person_mountain_biking_tone5:"] = "\uD83D\uDEB5\uD83C\uDFFF", + [":person_playing_handball:"] = "\uD83E\uDD3E", + [":person_playing_handball::skin-tone-1:"] = "\uD83E\uDD3E\uD83C\uDFFB", + [":person_playing_handball::skin-tone-2:"] = "\uD83E\uDD3E\uD83C\uDFFC", + [":person_playing_handball::skin-tone-3:"] = "\uD83E\uDD3E\uD83C\uDFFD", + [":person_playing_handball::skin-tone-4:"] = "\uD83E\uDD3E\uD83C\uDFFE", + [":person_playing_handball::skin-tone-5:"] = "\uD83E\uDD3E\uD83C\uDFFF", + [":person_playing_handball_tone1:"] = "\uD83E\uDD3E\uD83C\uDFFB", + [":person_playing_handball_tone2:"] = "\uD83E\uDD3E\uD83C\uDFFC", + [":person_playing_handball_tone3:"] = "\uD83E\uDD3E\uD83C\uDFFD", + [":person_playing_handball_tone4:"] = "\uD83E\uDD3E\uD83C\uDFFE", + [":person_playing_handball_tone5:"] = "\uD83E\uDD3E\uD83C\uDFFF", + [":person_playing_water_polo:"] = "\uD83E\uDD3D", + [":person_playing_water_polo::skin-tone-1:"] = "\uD83E\uDD3D\uD83C\uDFFB", + [":person_playing_water_polo::skin-tone-2:"] = "\uD83E\uDD3D\uD83C\uDFFC", + [":person_playing_water_polo::skin-tone-3:"] = "\uD83E\uDD3D\uD83C\uDFFD", + [":person_playing_water_polo::skin-tone-4:"] = "\uD83E\uDD3D\uD83C\uDFFE", + [":person_playing_water_polo::skin-tone-5:"] = "\uD83E\uDD3D\uD83C\uDFFF", + [":person_playing_water_polo_tone1:"] = "\uD83E\uDD3D\uD83C\uDFFB", + [":person_playing_water_polo_tone2:"] = "\uD83E\uDD3D\uD83C\uDFFC", + [":person_playing_water_polo_tone3:"] = "\uD83E\uDD3D\uD83C\uDFFD", + [":person_playing_water_polo_tone4:"] = "\uD83E\uDD3D\uD83C\uDFFE", + [":person_playing_water_polo_tone5:"] = "\uD83E\uDD3D\uD83C\uDFFF", + [":person_pouting:"] = "\uD83D\uDE4E", + [":person_pouting::skin-tone-1:"] = "\uD83D\uDE4E\uD83C\uDFFB", + [":person_pouting::skin-tone-2:"] = "\uD83D\uDE4E\uD83C\uDFFC", + [":person_pouting::skin-tone-3:"] = "\uD83D\uDE4E\uD83C\uDFFD", + [":person_pouting::skin-tone-4:"] = "\uD83D\uDE4E\uD83C\uDFFE", + [":person_pouting::skin-tone-5:"] = "\uD83D\uDE4E\uD83C\uDFFF", + [":person_pouting_tone1:"] = "\uD83D\uDE4E\uD83C\uDFFB", + [":person_pouting_tone2:"] = "\uD83D\uDE4E\uD83C\uDFFC", + [":person_pouting_tone3:"] = "\uD83D\uDE4E\uD83C\uDFFD", + [":person_pouting_tone4:"] = "\uD83D\uDE4E\uD83C\uDFFE", + [":person_pouting_tone5:"] = "\uD83D\uDE4E\uD83C\uDFFF", + [":person_raising_hand:"] = "\uD83D\uDE4B", + [":person_raising_hand::skin-tone-1:"] = "\uD83D\uDE4B\uD83C\uDFFB", + [":person_raising_hand::skin-tone-2:"] = "\uD83D\uDE4B\uD83C\uDFFC", + [":person_raising_hand::skin-tone-3:"] = "\uD83D\uDE4B\uD83C\uDFFD", + [":person_raising_hand::skin-tone-4:"] = "\uD83D\uDE4B\uD83C\uDFFE", + [":person_raising_hand::skin-tone-5:"] = "\uD83D\uDE4B\uD83C\uDFFF", + [":person_raising_hand_tone1:"] = "\uD83D\uDE4B\uD83C\uDFFB", + [":person_raising_hand_tone2:"] = "\uD83D\uDE4B\uD83C\uDFFC", + [":person_raising_hand_tone3:"] = "\uD83D\uDE4B\uD83C\uDFFD", + [":person_raising_hand_tone4:"] = "\uD83D\uDE4B\uD83C\uDFFE", + [":person_raising_hand_tone5:"] = "\uD83D\uDE4B\uD83C\uDFFF", + [":person_rowing_boat:"] = "\uD83D\uDEA3", + [":person_rowing_boat::skin-tone-1:"] = "\uD83D\uDEA3\uD83C\uDFFB", + [":person_rowing_boat::skin-tone-2:"] = "\uD83D\uDEA3\uD83C\uDFFC", + [":person_rowing_boat::skin-tone-3:"] = "\uD83D\uDEA3\uD83C\uDFFD", + [":person_rowing_boat::skin-tone-4:"] = "\uD83D\uDEA3\uD83C\uDFFE", + [":person_rowing_boat::skin-tone-5:"] = "\uD83D\uDEA3\uD83C\uDFFF", + [":person_rowing_boat_tone1:"] = "\uD83D\uDEA3\uD83C\uDFFB", + [":person_rowing_boat_tone2:"] = "\uD83D\uDEA3\uD83C\uDFFC", + [":person_rowing_boat_tone3:"] = "\uD83D\uDEA3\uD83C\uDFFD", + [":person_rowing_boat_tone4:"] = "\uD83D\uDEA3\uD83C\uDFFE", + [":person_rowing_boat_tone5:"] = "\uD83D\uDEA3\uD83C\uDFFF", + [":person_running:"] = "\uD83C\uDFC3", + [":person_running::skin-tone-1:"] = "\uD83C\uDFC3\uD83C\uDFFB", + [":person_running::skin-tone-2:"] = "\uD83C\uDFC3\uD83C\uDFFC", + [":person_running::skin-tone-3:"] = "\uD83C\uDFC3\uD83C\uDFFD", + [":person_running::skin-tone-4:"] = "\uD83C\uDFC3\uD83C\uDFFE", + [":person_running::skin-tone-5:"] = "\uD83C\uDFC3\uD83C\uDFFF", + [":person_running_tone1:"] = "\uD83C\uDFC3\uD83C\uDFFB", + [":person_running_tone2:"] = "\uD83C\uDFC3\uD83C\uDFFC", + [":person_running_tone3:"] = "\uD83C\uDFC3\uD83C\uDFFD", + [":person_running_tone4:"] = "\uD83C\uDFC3\uD83C\uDFFE", + [":person_running_tone5:"] = "\uD83C\uDFC3\uD83C\uDFFF", + [":person_shrugging:"] = "\uD83E\uDD37", + [":person_shrugging::skin-tone-1:"] = "\uD83E\uDD37\uD83C\uDFFB", + [":person_shrugging::skin-tone-2:"] = "\uD83E\uDD37\uD83C\uDFFC", + [":person_shrugging::skin-tone-3:"] = "\uD83E\uDD37\uD83C\uDFFD", + [":person_shrugging::skin-tone-4:"] = "\uD83E\uDD37\uD83C\uDFFE", + [":person_shrugging::skin-tone-5:"] = "\uD83E\uDD37\uD83C\uDFFF", + [":person_shrugging_tone1:"] = "\uD83E\uDD37\uD83C\uDFFB", + [":person_shrugging_tone2:"] = "\uD83E\uDD37\uD83C\uDFFC", + [":person_shrugging_tone3:"] = "\uD83E\uDD37\uD83C\uDFFD", + [":person_shrugging_tone4:"] = "\uD83E\uDD37\uD83C\uDFFE", + [":person_shrugging_tone5:"] = "\uD83E\uDD37\uD83C\uDFFF", + [":person_standing:"] = "\uD83E\uDDCD", + [":person_standing::skin-tone-1:"] = "\uD83E\uDDCD\uD83C\uDFFB", + [":person_standing::skin-tone-2:"] = "\uD83E\uDDCD\uD83C\uDFFC", + [":person_standing::skin-tone-3:"] = "\uD83E\uDDCD\uD83C\uDFFD", + [":person_standing::skin-tone-4:"] = "\uD83E\uDDCD\uD83C\uDFFE", + [":person_standing::skin-tone-5:"] = "\uD83E\uDDCD\uD83C\uDFFF", + [":person_standing_dark_skin_tone:"] = "\uD83E\uDDCD\uD83C\uDFFF", + [":person_standing_light_skin_tone:"] = "\uD83E\uDDCD\uD83C\uDFFB", + [":person_standing_medium_dark_skin_tone:"] = "\uD83E\uDDCD\uD83C\uDFFE", + [":person_standing_medium_light_skin_tone:"] = "\uD83E\uDDCD\uD83C\uDFFC", + [":person_standing_medium_skin_tone:"] = "\uD83E\uDDCD\uD83C\uDFFD", + [":person_standing_tone1:"] = "\uD83E\uDDCD\uD83C\uDFFB", + [":person_standing_tone2:"] = "\uD83E\uDDCD\uD83C\uDFFC", + [":person_standing_tone3:"] = "\uD83E\uDDCD\uD83C\uDFFD", + [":person_standing_tone4:"] = "\uD83E\uDDCD\uD83C\uDFFE", + [":person_standing_tone5:"] = "\uD83E\uDDCD\uD83C\uDFFF", + [":person_surfing:"] = "\uD83C\uDFC4", + [":person_surfing::skin-tone-1:"] = "\uD83C\uDFC4\uD83C\uDFFB", + [":person_surfing::skin-tone-2:"] = "\uD83C\uDFC4\uD83C\uDFFC", + [":person_surfing::skin-tone-3:"] = "\uD83C\uDFC4\uD83C\uDFFD", + [":person_surfing::skin-tone-4:"] = "\uD83C\uDFC4\uD83C\uDFFE", + [":person_surfing::skin-tone-5:"] = "\uD83C\uDFC4\uD83C\uDFFF", + [":person_surfing_tone1:"] = "\uD83C\uDFC4\uD83C\uDFFB", + [":person_surfing_tone2:"] = "\uD83C\uDFC4\uD83C\uDFFC", + [":person_surfing_tone3:"] = "\uD83C\uDFC4\uD83C\uDFFD", + [":person_surfing_tone4:"] = "\uD83C\uDFC4\uD83C\uDFFE", + [":person_surfing_tone5:"] = "\uD83C\uDFC4\uD83C\uDFFF", + [":person_swimming:"] = "\uD83C\uDFCA", + [":person_swimming::skin-tone-1:"] = "\uD83C\uDFCA\uD83C\uDFFB", + [":person_swimming::skin-tone-2:"] = "\uD83C\uDFCA\uD83C\uDFFC", + [":person_swimming::skin-tone-3:"] = "\uD83C\uDFCA\uD83C\uDFFD", + [":person_swimming::skin-tone-4:"] = "\uD83C\uDFCA\uD83C\uDFFE", + [":person_swimming::skin-tone-5:"] = "\uD83C\uDFCA\uD83C\uDFFF", + [":person_swimming_tone1:"] = "\uD83C\uDFCA\uD83C\uDFFB", + [":person_swimming_tone2:"] = "\uD83C\uDFCA\uD83C\uDFFC", + [":person_swimming_tone3:"] = "\uD83C\uDFCA\uD83C\uDFFD", + [":person_swimming_tone4:"] = "\uD83C\uDFCA\uD83C\uDFFE", + [":person_swimming_tone5:"] = "\uD83C\uDFCA\uD83C\uDFFF", + [":person_tipping_hand:"] = "\uD83D\uDC81", + [":person_tipping_hand::skin-tone-1:"] = "\uD83D\uDC81\uD83C\uDFFB", + [":person_tipping_hand::skin-tone-2:"] = "\uD83D\uDC81\uD83C\uDFFC", + [":person_tipping_hand::skin-tone-3:"] = "\uD83D\uDC81\uD83C\uDFFD", + [":person_tipping_hand::skin-tone-4:"] = "\uD83D\uDC81\uD83C\uDFFE", + [":person_tipping_hand::skin-tone-5:"] = "\uD83D\uDC81\uD83C\uDFFF", + [":person_tipping_hand_tone1:"] = "\uD83D\uDC81\uD83C\uDFFB", + [":person_tipping_hand_tone2:"] = "\uD83D\uDC81\uD83C\uDFFC", + [":person_tipping_hand_tone3:"] = "\uD83D\uDC81\uD83C\uDFFD", + [":person_tipping_hand_tone4:"] = "\uD83D\uDC81\uD83C\uDFFE", + [":person_tipping_hand_tone5:"] = "\uD83D\uDC81\uD83C\uDFFF", + [":person_walking:"] = "\uD83D\uDEB6", + [":person_walking::skin-tone-1:"] = "\uD83D\uDEB6\uD83C\uDFFB", + [":person_walking::skin-tone-2:"] = "\uD83D\uDEB6\uD83C\uDFFC", + [":person_walking::skin-tone-3:"] = "\uD83D\uDEB6\uD83C\uDFFD", + [":person_walking::skin-tone-4:"] = "\uD83D\uDEB6\uD83C\uDFFE", + [":person_walking::skin-tone-5:"] = "\uD83D\uDEB6\uD83C\uDFFF", + [":person_walking_tone1:"] = "\uD83D\uDEB6\uD83C\uDFFB", + [":person_walking_tone2:"] = "\uD83D\uDEB6\uD83C\uDFFC", + [":person_walking_tone3:"] = "\uD83D\uDEB6\uD83C\uDFFD", + [":person_walking_tone4:"] = "\uD83D\uDEB6\uD83C\uDFFE", + [":person_walking_tone5:"] = "\uD83D\uDEB6\uD83C\uDFFF", + [":person_wearing_turban:"] = "\uD83D\uDC73", + [":person_wearing_turban::skin-tone-1:"] = "\uD83D\uDC73\uD83C\uDFFB", + [":person_wearing_turban::skin-tone-2:"] = "\uD83D\uDC73\uD83C\uDFFC", + [":person_wearing_turban::skin-tone-3:"] = "\uD83D\uDC73\uD83C\uDFFD", + [":person_wearing_turban::skin-tone-4:"] = "\uD83D\uDC73\uD83C\uDFFE", + [":person_wearing_turban::skin-tone-5:"] = "\uD83D\uDC73\uD83C\uDFFF", + [":person_wearing_turban_tone1:"] = "\uD83D\uDC73\uD83C\uDFFB", + [":person_wearing_turban_tone2:"] = "\uD83D\uDC73\uD83C\uDFFC", + [":person_wearing_turban_tone3:"] = "\uD83D\uDC73\uD83C\uDFFD", + [":person_wearing_turban_tone4:"] = "\uD83D\uDC73\uD83C\uDFFE", + [":person_wearing_turban_tone5:"] = "\uD83D\uDC73\uD83C\uDFFF", + [":person_with_ball:"] = "⛹️", + [":person_with_ball::skin-tone-1:"] = "⛹\uD83C\uDFFB", + [":person_with_ball::skin-tone-2:"] = "⛹\uD83C\uDFFC", + [":person_with_ball::skin-tone-3:"] = "⛹\uD83C\uDFFD", + [":person_with_ball::skin-tone-4:"] = "⛹\uD83C\uDFFE", + [":person_with_ball::skin-tone-5:"] = "⛹\uD83C\uDFFF", + [":person_with_ball_tone1:"] = "⛹\uD83C\uDFFB", + [":person_with_ball_tone2:"] = "⛹\uD83C\uDFFC", + [":person_with_ball_tone3:"] = "⛹\uD83C\uDFFD", + [":person_with_ball_tone4:"] = "⛹\uD83C\uDFFE", + [":person_with_ball_tone5:"] = "⛹\uD83C\uDFFF", + [":person_with_blond_hair:"] = "\uD83D\uDC71", + [":person_with_blond_hair::skin-tone-1:"] = "\uD83D\uDC71\uD83C\uDFFB", + [":person_with_blond_hair::skin-tone-2:"] = "\uD83D\uDC71\uD83C\uDFFC", + [":person_with_blond_hair::skin-tone-3:"] = "\uD83D\uDC71\uD83C\uDFFD", + [":person_with_blond_hair::skin-tone-4:"] = "\uD83D\uDC71\uD83C\uDFFE", + [":person_with_blond_hair::skin-tone-5:"] = "\uD83D\uDC71\uD83C\uDFFF", + [":person_with_blond_hair_tone1:"] = "\uD83D\uDC71\uD83C\uDFFB", + [":person_with_blond_hair_tone2:"] = "\uD83D\uDC71\uD83C\uDFFC", + [":person_with_blond_hair_tone3:"] = "\uD83D\uDC71\uD83C\uDFFD", + [":person_with_blond_hair_tone4:"] = "\uD83D\uDC71\uD83C\uDFFE", + [":person_with_blond_hair_tone5:"] = "\uD83D\uDC71\uD83C\uDFFF", + [":person_with_pouting_face:"] = "\uD83D\uDE4E", + [":person_with_pouting_face::skin-tone-1:"] = "\uD83D\uDE4E\uD83C\uDFFB", + [":person_with_pouting_face::skin-tone-2:"] = "\uD83D\uDE4E\uD83C\uDFFC", + [":person_with_pouting_face::skin-tone-3:"] = "\uD83D\uDE4E\uD83C\uDFFD", + [":person_with_pouting_face::skin-tone-4:"] = "\uD83D\uDE4E\uD83C\uDFFE", + [":person_with_pouting_face::skin-tone-5:"] = "\uD83D\uDE4E\uD83C\uDFFF", + [":person_with_pouting_face_tone1:"] = "\uD83D\uDE4E\uD83C\uDFFB", + [":person_with_pouting_face_tone2:"] = "\uD83D\uDE4E\uD83C\uDFFC", + [":person_with_pouting_face_tone3:"] = "\uD83D\uDE4E\uD83C\uDFFD", + [":person_with_pouting_face_tone4:"] = "\uD83D\uDE4E\uD83C\uDFFE", + [":person_with_pouting_face_tone5:"] = "\uD83D\uDE4E\uD83C\uDFFF", + [":petri_dish:"] = "\uD83E\uDDEB", + [":pick:"] = "⛏️", + [":pie:"] = "\uD83E\uDD67", + [":pig2:"] = "\uD83D\uDC16", + [":pig:"] = "\uD83D\uDC37", + [":pig_nose:"] = "\uD83D\uDC3D", + [":pill:"] = "\uD83D\uDC8A", + [":pinching_hand:"] = "\uD83E\uDD0F", + [":pinching_hand::skin-tone-1:"] = "\uD83E\uDD0F\uD83C\uDFFB", + [":pinching_hand::skin-tone-2:"] = "\uD83E\uDD0F\uD83C\uDFFC", + [":pinching_hand::skin-tone-3:"] = "\uD83E\uDD0F\uD83C\uDFFD", + [":pinching_hand::skin-tone-4:"] = "\uD83E\uDD0F\uD83C\uDFFE", + [":pinching_hand::skin-tone-5:"] = "\uD83E\uDD0F\uD83C\uDFFF", + [":pinching_hand_dark_skin_tone:"] = "\uD83E\uDD0F\uD83C\uDFFF", + [":pinching_hand_light_skin_tone:"] = "\uD83E\uDD0F\uD83C\uDFFB", + [":pinching_hand_medium_dark_skin_tone:"] = "\uD83E\uDD0F\uD83C\uDFFE", + [":pinching_hand_medium_light_skin_tone:"] = "\uD83E\uDD0F\uD83C\uDFFC", + [":pinching_hand_medium_skin_tone:"] = "\uD83E\uDD0F\uD83C\uDFFD", + [":pinching_hand_tone1:"] = "\uD83E\uDD0F\uD83C\uDFFB", + [":pinching_hand_tone2:"] = "\uD83E\uDD0F\uD83C\uDFFC", + [":pinching_hand_tone3:"] = "\uD83E\uDD0F\uD83C\uDFFD", + [":pinching_hand_tone4:"] = "\uD83E\uDD0F\uD83C\uDFFE", + [":pinching_hand_tone5:"] = "\uD83E\uDD0F\uD83C\uDFFF", + [":pineapple:"] = "\uD83C\uDF4D", + [":ping_pong:"] = "\uD83C\uDFD3", + [":pirate_flag:"] = "\uD83C\uDFF4\u200D☠️", + [":pisces:"] = "♓", + [":pizza:"] = "\uD83C\uDF55", + [":place_of_worship:"] = "\uD83D\uDED0", + [":play_pause:"] = "⏯️", + [":pleading_face:"] = "\uD83E\uDD7A", + [":point_down:"] = "\uD83D\uDC47", + [":point_down::skin-tone-1:"] = "\uD83D\uDC47\uD83C\uDFFB", + [":point_down::skin-tone-2:"] = "\uD83D\uDC47\uD83C\uDFFC", + [":point_down::skin-tone-3:"] = "\uD83D\uDC47\uD83C\uDFFD", + [":point_down::skin-tone-4:"] = "\uD83D\uDC47\uD83C\uDFFE", + [":point_down::skin-tone-5:"] = "\uD83D\uDC47\uD83C\uDFFF", + [":point_down_tone1:"] = "\uD83D\uDC47\uD83C\uDFFB", + [":point_down_tone2:"] = "\uD83D\uDC47\uD83C\uDFFC", + [":point_down_tone3:"] = "\uD83D\uDC47\uD83C\uDFFD", + [":point_down_tone4:"] = "\uD83D\uDC47\uD83C\uDFFE", + [":point_down_tone5:"] = "\uD83D\uDC47\uD83C\uDFFF", + [":point_left:"] = "\uD83D\uDC48", + [":point_left::skin-tone-1:"] = "\uD83D\uDC48\uD83C\uDFFB", + [":point_left::skin-tone-2:"] = "\uD83D\uDC48\uD83C\uDFFC", + [":point_left::skin-tone-3:"] = "\uD83D\uDC48\uD83C\uDFFD", + [":point_left::skin-tone-4:"] = "\uD83D\uDC48\uD83C\uDFFE", + [":point_left::skin-tone-5:"] = "\uD83D\uDC48\uD83C\uDFFF", + [":point_left_tone1:"] = "\uD83D\uDC48\uD83C\uDFFB", + [":point_left_tone2:"] = "\uD83D\uDC48\uD83C\uDFFC", + [":point_left_tone3:"] = "\uD83D\uDC48\uD83C\uDFFD", + [":point_left_tone4:"] = "\uD83D\uDC48\uD83C\uDFFE", + [":point_left_tone5:"] = "\uD83D\uDC48\uD83C\uDFFF", + [":point_right:"] = "\uD83D\uDC49", + [":point_right::skin-tone-1:"] = "\uD83D\uDC49\uD83C\uDFFB", + [":point_right::skin-tone-2:"] = "\uD83D\uDC49\uD83C\uDFFC", + [":point_right::skin-tone-3:"] = "\uD83D\uDC49\uD83C\uDFFD", + [":point_right::skin-tone-4:"] = "\uD83D\uDC49\uD83C\uDFFE", + [":point_right::skin-tone-5:"] = "\uD83D\uDC49\uD83C\uDFFF", + [":point_right_tone1:"] = "\uD83D\uDC49\uD83C\uDFFB", + [":point_right_tone2:"] = "\uD83D\uDC49\uD83C\uDFFC", + [":point_right_tone3:"] = "\uD83D\uDC49\uD83C\uDFFD", + [":point_right_tone4:"] = "\uD83D\uDC49\uD83C\uDFFE", + [":point_right_tone5:"] = "\uD83D\uDC49\uD83C\uDFFF", + [":point_up:"] = "☝️", + [":point_up::skin-tone-1:"] = "☝\uD83C\uDFFB", + [":point_up::skin-tone-2:"] = "☝\uD83C\uDFFC", + [":point_up::skin-tone-3:"] = "☝\uD83C\uDFFD", + [":point_up::skin-tone-4:"] = "☝\uD83C\uDFFE", + [":point_up::skin-tone-5:"] = "☝\uD83C\uDFFF", + [":point_up_2:"] = "\uD83D\uDC46", + [":point_up_2::skin-tone-1:"] = "\uD83D\uDC46\uD83C\uDFFB", + [":point_up_2::skin-tone-2:"] = "\uD83D\uDC46\uD83C\uDFFC", + [":point_up_2::skin-tone-3:"] = "\uD83D\uDC46\uD83C\uDFFD", + [":point_up_2::skin-tone-4:"] = "\uD83D\uDC46\uD83C\uDFFE", + [":point_up_2::skin-tone-5:"] = "\uD83D\uDC46\uD83C\uDFFF", + [":point_up_2_tone1:"] = "\uD83D\uDC46\uD83C\uDFFB", + [":point_up_2_tone2:"] = "\uD83D\uDC46\uD83C\uDFFC", + [":point_up_2_tone3:"] = "\uD83D\uDC46\uD83C\uDFFD", + [":point_up_2_tone4:"] = "\uD83D\uDC46\uD83C\uDFFE", + [":point_up_2_tone5:"] = "\uD83D\uDC46\uD83C\uDFFF", + [":point_up_tone1:"] = "☝\uD83C\uDFFB", + [":point_up_tone2:"] = "☝\uD83C\uDFFC", + [":point_up_tone3:"] = "☝\uD83C\uDFFD", + [":point_up_tone4:"] = "☝\uD83C\uDFFE", + [":point_up_tone5:"] = "☝\uD83C\uDFFF", + [":police_car:"] = "\uD83D\uDE93", + [":police_officer:"] = "\uD83D\uDC6E", + [":police_officer::skin-tone-1:"] = "\uD83D\uDC6E\uD83C\uDFFB", + [":police_officer::skin-tone-2:"] = "\uD83D\uDC6E\uD83C\uDFFC", + [":police_officer::skin-tone-3:"] = "\uD83D\uDC6E\uD83C\uDFFD", + [":police_officer::skin-tone-4:"] = "\uD83D\uDC6E\uD83C\uDFFE", + [":police_officer::skin-tone-5:"] = "\uD83D\uDC6E\uD83C\uDFFF", + [":police_officer_tone1:"] = "\uD83D\uDC6E\uD83C\uDFFB", + [":police_officer_tone2:"] = "\uD83D\uDC6E\uD83C\uDFFC", + [":police_officer_tone3:"] = "\uD83D\uDC6E\uD83C\uDFFD", + [":police_officer_tone4:"] = "\uD83D\uDC6E\uD83C\uDFFE", + [":police_officer_tone5:"] = "\uD83D\uDC6E\uD83C\uDFFF", + [":poo:"] = "\uD83D\uDCA9", + [":poodle:"] = "\uD83D\uDC29", + [":poop:"] = "\uD83D\uDCA9", + [":popcorn:"] = "\uD83C\uDF7F", + [":post_office:"] = "\uD83C\uDFE3", + [":postal_horn:"] = "\uD83D\uDCEF", + [":postbox:"] = "\uD83D\uDCEE", + [":potable_water:"] = "\uD83D\uDEB0", + [":potato:"] = "\uD83E\uDD54", + [":pouch:"] = "\uD83D\uDC5D", + [":poultry_leg:"] = "\uD83C\uDF57", + [":pound:"] = "\uD83D\uDCB7", + [":pouting_cat:"] = "\uD83D\uDE3E", + [":pray:"] = "\uD83D\uDE4F", + [":pray::skin-tone-1:"] = "\uD83D\uDE4F\uD83C\uDFFB", + [":pray::skin-tone-2:"] = "\uD83D\uDE4F\uD83C\uDFFC", + [":pray::skin-tone-3:"] = "\uD83D\uDE4F\uD83C\uDFFD", + [":pray::skin-tone-4:"] = "\uD83D\uDE4F\uD83C\uDFFE", + [":pray::skin-tone-5:"] = "\uD83D\uDE4F\uD83C\uDFFF", + [":pray_tone1:"] = "\uD83D\uDE4F\uD83C\uDFFB", + [":pray_tone2:"] = "\uD83D\uDE4F\uD83C\uDFFC", + [":pray_tone3:"] = "\uD83D\uDE4F\uD83C\uDFFD", + [":pray_tone4:"] = "\uD83D\uDE4F\uD83C\uDFFE", + [":pray_tone5:"] = "\uD83D\uDE4F\uD83C\uDFFF", + [":prayer_beads:"] = "\uD83D\uDCFF", + [":pregnant_woman:"] = "\uD83E\uDD30", + [":pregnant_woman::skin-tone-1:"] = "\uD83E\uDD30\uD83C\uDFFB", + [":pregnant_woman::skin-tone-2:"] = "\uD83E\uDD30\uD83C\uDFFC", + [":pregnant_woman::skin-tone-3:"] = "\uD83E\uDD30\uD83C\uDFFD", + [":pregnant_woman::skin-tone-4:"] = "\uD83E\uDD30\uD83C\uDFFE", + [":pregnant_woman::skin-tone-5:"] = "\uD83E\uDD30\uD83C\uDFFF", + [":pregnant_woman_tone1:"] = "\uD83E\uDD30\uD83C\uDFFB", + [":pregnant_woman_tone2:"] = "\uD83E\uDD30\uD83C\uDFFC", + [":pregnant_woman_tone3:"] = "\uD83E\uDD30\uD83C\uDFFD", + [":pregnant_woman_tone4:"] = "\uD83E\uDD30\uD83C\uDFFE", + [":pregnant_woman_tone5:"] = "\uD83E\uDD30\uD83C\uDFFF", + [":pretzel:"] = "\uD83E\uDD68", + [":previous_track:"] = "⏮️", + [":prince:"] = "\uD83E\uDD34", + [":prince::skin-tone-1:"] = "\uD83E\uDD34\uD83C\uDFFB", + [":prince::skin-tone-2:"] = "\uD83E\uDD34\uD83C\uDFFC", + [":prince::skin-tone-3:"] = "\uD83E\uDD34\uD83C\uDFFD", + [":prince::skin-tone-4:"] = "\uD83E\uDD34\uD83C\uDFFE", + [":prince::skin-tone-5:"] = "\uD83E\uDD34\uD83C\uDFFF", + [":prince_tone1:"] = "\uD83E\uDD34\uD83C\uDFFB", + [":prince_tone2:"] = "\uD83E\uDD34\uD83C\uDFFC", + [":prince_tone3:"] = "\uD83E\uDD34\uD83C\uDFFD", + [":prince_tone4:"] = "\uD83E\uDD34\uD83C\uDFFE", + [":prince_tone5:"] = "\uD83E\uDD34\uD83C\uDFFF", + [":princess:"] = "\uD83D\uDC78", + [":princess::skin-tone-1:"] = "\uD83D\uDC78\uD83C\uDFFB", + [":princess::skin-tone-2:"] = "\uD83D\uDC78\uD83C\uDFFC", + [":princess::skin-tone-3:"] = "\uD83D\uDC78\uD83C\uDFFD", + [":princess::skin-tone-4:"] = "\uD83D\uDC78\uD83C\uDFFE", + [":princess::skin-tone-5:"] = "\uD83D\uDC78\uD83C\uDFFF", + [":princess_tone1:"] = "\uD83D\uDC78\uD83C\uDFFB", + [":princess_tone2:"] = "\uD83D\uDC78\uD83C\uDFFC", + [":princess_tone3:"] = "\uD83D\uDC78\uD83C\uDFFD", + [":princess_tone4:"] = "\uD83D\uDC78\uD83C\uDFFE", + [":princess_tone5:"] = "\uD83D\uDC78\uD83C\uDFFF", + [":printer:"] = "\uD83D\uDDA8️", + [":probing_cane:"] = "\uD83E\uDDAF", + [":projector:"] = "\uD83D\uDCFD️", + [":pudding:"] = "\uD83C\uDF6E", + [":punch:"] = "\uD83D\uDC4A", + [":punch::skin-tone-1:"] = "\uD83D\uDC4A\uD83C\uDFFB", + [":punch::skin-tone-2:"] = "\uD83D\uDC4A\uD83C\uDFFC", + [":punch::skin-tone-3:"] = "\uD83D\uDC4A\uD83C\uDFFD", + [":punch::skin-tone-4:"] = "\uD83D\uDC4A\uD83C\uDFFE", + [":punch::skin-tone-5:"] = "\uD83D\uDC4A\uD83C\uDFFF", + [":punch_tone1:"] = "\uD83D\uDC4A\uD83C\uDFFB", + [":punch_tone2:"] = "\uD83D\uDC4A\uD83C\uDFFC", + [":punch_tone3:"] = "\uD83D\uDC4A\uD83C\uDFFD", + [":punch_tone4:"] = "\uD83D\uDC4A\uD83C\uDFFE", + [":punch_tone5:"] = "\uD83D\uDC4A\uD83C\uDFFF", + [":purple_circle:"] = "\uD83D\uDFE3", + [":purple_heart:"] = "\uD83D\uDC9C", + [":purple_square:"] = "\uD83D\uDFEA", + [":purse:"] = "\uD83D\uDC5B", + [":pushpin:"] = "\uD83D\uDCCC", + [":put_litter_in_its_place:"] = "\uD83D\uDEAE", + [":question:"] = "❓", + [":rabbit2:"] = "\uD83D\uDC07", + [":rabbit:"] = "\uD83D\uDC30", + [":raccoon:"] = "\uD83E\uDD9D", + [":race_car:"] = "\uD83C\uDFCE️", + [":racehorse:"] = "\uD83D\uDC0E", + [":racing_car:"] = "\uD83C\uDFCE️", + [":racing_motorcycle:"] = "\uD83C\uDFCD️", + [":radio:"] = "\uD83D\uDCFB", + [":radio_button:"] = "\uD83D\uDD18", + [":radioactive:"] = "☢️", + [":radioactive_sign:"] = "☢️", + [":rage:"] = "\uD83D\uDE21", + [":railroad_track:"] = "\uD83D\uDEE4️", + [":railway_car:"] = "\uD83D\uDE83", + [":railway_track:"] = "\uD83D\uDEE4️", + [":rainbow:"] = "\uD83C\uDF08", + [":rainbow_flag:"] = "\uD83C\uDFF3️\u200D\uD83C\uDF08", + [":raised_back_of_hand:"] = "\uD83E\uDD1A", + [":raised_back_of_hand::skin-tone-1:"] = "\uD83E\uDD1A\uD83C\uDFFB", + [":raised_back_of_hand::skin-tone-2:"] = "\uD83E\uDD1A\uD83C\uDFFC", + [":raised_back_of_hand::skin-tone-3:"] = "\uD83E\uDD1A\uD83C\uDFFD", + [":raised_back_of_hand::skin-tone-4:"] = "\uD83E\uDD1A\uD83C\uDFFE", + [":raised_back_of_hand::skin-tone-5:"] = "\uD83E\uDD1A\uD83C\uDFFF", + [":raised_back_of_hand_tone1:"] = "\uD83E\uDD1A\uD83C\uDFFB", + [":raised_back_of_hand_tone2:"] = "\uD83E\uDD1A\uD83C\uDFFC", + [":raised_back_of_hand_tone3:"] = "\uD83E\uDD1A\uD83C\uDFFD", + [":raised_back_of_hand_tone4:"] = "\uD83E\uDD1A\uD83C\uDFFE", + [":raised_back_of_hand_tone5:"] = "\uD83E\uDD1A\uD83C\uDFFF", + [":raised_hand:"] = "✋", + [":raised_hand::skin-tone-1:"] = "✋\uD83C\uDFFB", + [":raised_hand::skin-tone-2:"] = "✋\uD83C\uDFFC", + [":raised_hand::skin-tone-3:"] = "✋\uD83C\uDFFD", + [":raised_hand::skin-tone-4:"] = "✋\uD83C\uDFFE", + [":raised_hand::skin-tone-5:"] = "✋\uD83C\uDFFF", + [":raised_hand_tone1:"] = "✋\uD83C\uDFFB", + [":raised_hand_tone2:"] = "✋\uD83C\uDFFC", + [":raised_hand_tone3:"] = "✋\uD83C\uDFFD", + [":raised_hand_tone4:"] = "✋\uD83C\uDFFE", + [":raised_hand_tone5:"] = "✋\uD83C\uDFFF", + [":raised_hand_with_fingers_splayed:"] = "\uD83D\uDD90️", + [":raised_hand_with_fingers_splayed::skin-tone-1:"] = "\uD83D\uDD90\uD83C\uDFFB", + [":raised_hand_with_fingers_splayed::skin-tone-2:"] = "\uD83D\uDD90\uD83C\uDFFC", + [":raised_hand_with_fingers_splayed::skin-tone-3:"] = "\uD83D\uDD90\uD83C\uDFFD", + [":raised_hand_with_fingers_splayed::skin-tone-4:"] = "\uD83D\uDD90\uD83C\uDFFE", + [":raised_hand_with_fingers_splayed::skin-tone-5:"] = "\uD83D\uDD90\uD83C\uDFFF", + [":raised_hand_with_fingers_splayed_tone1:"] = "\uD83D\uDD90\uD83C\uDFFB", + [":raised_hand_with_fingers_splayed_tone2:"] = "\uD83D\uDD90\uD83C\uDFFC", + [":raised_hand_with_fingers_splayed_tone3:"] = "\uD83D\uDD90\uD83C\uDFFD", + [":raised_hand_with_fingers_splayed_tone4:"] = "\uD83D\uDD90\uD83C\uDFFE", + [":raised_hand_with_fingers_splayed_tone5:"] = "\uD83D\uDD90\uD83C\uDFFF", + [":raised_hand_with_part_between_middle_and_ring_fingers:"] = "\uD83D\uDD96", + [":raised_hand_with_part_between_middle_and_ring_fingers::skin-tone-1:"] = "\uD83D\uDD96\uD83C\uDFFB", + [":raised_hand_with_part_between_middle_and_ring_fingers::skin-tone-2:"] = "\uD83D\uDD96\uD83C\uDFFC", + [":raised_hand_with_part_between_middle_and_ring_fingers::skin-tone-3:"] = "\uD83D\uDD96\uD83C\uDFFD", + [":raised_hand_with_part_between_middle_and_ring_fingers::skin-tone-4:"] = "\uD83D\uDD96\uD83C\uDFFE", + [":raised_hand_with_part_between_middle_and_ring_fingers::skin-tone-5:"] = "\uD83D\uDD96\uD83C\uDFFF", + [":raised_hand_with_part_between_middle_and_ring_fingers_tone1:"] = "\uD83D\uDD96\uD83C\uDFFB", + [":raised_hand_with_part_between_middle_and_ring_fingers_tone2:"] = "\uD83D\uDD96\uD83C\uDFFC", + [":raised_hand_with_part_between_middle_and_ring_fingers_tone3:"] = "\uD83D\uDD96\uD83C\uDFFD", + [":raised_hand_with_part_between_middle_and_ring_fingers_tone4:"] = "\uD83D\uDD96\uD83C\uDFFE", + [":raised_hand_with_part_between_middle_and_ring_fingers_tone5:"] = "\uD83D\uDD96\uD83C\uDFFF", + [":raised_hands:"] = "\uD83D\uDE4C", + [":raised_hands::skin-tone-1:"] = "\uD83D\uDE4C\uD83C\uDFFB", + [":raised_hands::skin-tone-2:"] = "\uD83D\uDE4C\uD83C\uDFFC", + [":raised_hands::skin-tone-3:"] = "\uD83D\uDE4C\uD83C\uDFFD", + [":raised_hands::skin-tone-4:"] = "\uD83D\uDE4C\uD83C\uDFFE", + [":raised_hands::skin-tone-5:"] = "\uD83D\uDE4C\uD83C\uDFFF", + [":raised_hands_tone1:"] = "\uD83D\uDE4C\uD83C\uDFFB", + [":raised_hands_tone2:"] = "\uD83D\uDE4C\uD83C\uDFFC", + [":raised_hands_tone3:"] = "\uD83D\uDE4C\uD83C\uDFFD", + [":raised_hands_tone4:"] = "\uD83D\uDE4C\uD83C\uDFFE", + [":raised_hands_tone5:"] = "\uD83D\uDE4C\uD83C\uDFFF", + [":raising_hand:"] = "\uD83D\uDE4B", + [":raising_hand::skin-tone-1:"] = "\uD83D\uDE4B\uD83C\uDFFB", + [":raising_hand::skin-tone-2:"] = "\uD83D\uDE4B\uD83C\uDFFC", + [":raising_hand::skin-tone-3:"] = "\uD83D\uDE4B\uD83C\uDFFD", + [":raising_hand::skin-tone-4:"] = "\uD83D\uDE4B\uD83C\uDFFE", + [":raising_hand::skin-tone-5:"] = "\uD83D\uDE4B\uD83C\uDFFF", + [":raising_hand_tone1:"] = "\uD83D\uDE4B\uD83C\uDFFB", + [":raising_hand_tone2:"] = "\uD83D\uDE4B\uD83C\uDFFC", + [":raising_hand_tone3:"] = "\uD83D\uDE4B\uD83C\uDFFD", + [":raising_hand_tone4:"] = "\uD83D\uDE4B\uD83C\uDFFE", + [":raising_hand_tone5:"] = "\uD83D\uDE4B\uD83C\uDFFF", + [":ram:"] = "\uD83D\uDC0F", + [":ramen:"] = "\uD83C\uDF5C", + [":rat:"] = "\uD83D\uDC00", + [":razor:"] = "\uD83E\uDE92", + [":receipt:"] = "\uD83E\uDDFE", + [":record_button:"] = "⏺️", + [":recycle:"] = "♻️", + [":red_car:"] = "\uD83D\uDE97", + [":red_circle:"] = "\uD83D\uDD34", + [":red_envelope:"] = "\uD83E\uDDE7", + [":red_square:"] = "\uD83D\uDFE5", + [":regional_indicator_a:"] = "\uD83C\uDDE6", + [":regional_indicator_b:"] = "\uD83C\uDDE7", + [":regional_indicator_c:"] = "\uD83C\uDDE8", + [":regional_indicator_d:"] = "\uD83C\uDDE9", + [":regional_indicator_e:"] = "\uD83C\uDDEA", + [":regional_indicator_f:"] = "\uD83C\uDDEB", + [":regional_indicator_g:"] = "\uD83C\uDDEC", + [":regional_indicator_h:"] = "\uD83C\uDDED", + [":regional_indicator_i:"] = "\uD83C\uDDEE", + [":regional_indicator_j:"] = "\uD83C\uDDEF", + [":regional_indicator_k:"] = "\uD83C\uDDF0", + [":regional_indicator_l:"] = "\uD83C\uDDF1", + [":regional_indicator_m:"] = "\uD83C\uDDF2", + [":regional_indicator_n:"] = "\uD83C\uDDF3", + [":regional_indicator_o:"] = "\uD83C\uDDF4", + [":regional_indicator_p:"] = "\uD83C\uDDF5", + [":regional_indicator_q:"] = "\uD83C\uDDF6", + [":regional_indicator_r:"] = "\uD83C\uDDF7", + [":regional_indicator_s:"] = "\uD83C\uDDF8", + [":regional_indicator_t:"] = "\uD83C\uDDF9", + [":regional_indicator_u:"] = "\uD83C\uDDFA", + [":regional_indicator_v:"] = "\uD83C\uDDFB", + [":regional_indicator_w:"] = "\uD83C\uDDFC", + [":regional_indicator_x:"] = "\uD83C\uDDFD", + [":regional_indicator_y:"] = "\uD83C\uDDFE", + [":regional_indicator_z:"] = "\uD83C\uDDFF", + [":registered:"] = "®️", + [":relaxed:"] = "☺️", + [":relieved:"] = "\uD83D\uDE0C", + [":reminder_ribbon:"] = "\uD83C\uDF97️", + [":repeat:"] = "\uD83D\uDD01", + [":repeat_one:"] = "\uD83D\uDD02", + [":restroom:"] = "\uD83D\uDEBB", + [":reversed_hand_with_middle_finger_extended:"] = "\uD83D\uDD95", + [":reversed_hand_with_middle_finger_extended::skin-tone-1:"] = "\uD83D\uDD95\uD83C\uDFFB", + [":reversed_hand_with_middle_finger_extended::skin-tone-2:"] = "\uD83D\uDD95\uD83C\uDFFC", + [":reversed_hand_with_middle_finger_extended::skin-tone-3:"] = "\uD83D\uDD95\uD83C\uDFFD", + [":reversed_hand_with_middle_finger_extended::skin-tone-4:"] = "\uD83D\uDD95\uD83C\uDFFE", + [":reversed_hand_with_middle_finger_extended::skin-tone-5:"] = "\uD83D\uDD95\uD83C\uDFFF", + [":reversed_hand_with_middle_finger_extended_tone1:"] = "\uD83D\uDD95\uD83C\uDFFB", + [":reversed_hand_with_middle_finger_extended_tone2:"] = "\uD83D\uDD95\uD83C\uDFFC", + [":reversed_hand_with_middle_finger_extended_tone3:"] = "\uD83D\uDD95\uD83C\uDFFD", + [":reversed_hand_with_middle_finger_extended_tone4:"] = "\uD83D\uDD95\uD83C\uDFFE", + [":reversed_hand_with_middle_finger_extended_tone5:"] = "\uD83D\uDD95\uD83C\uDFFF", + [":revolving_hearts:"] = "\uD83D\uDC9E", + [":rewind:"] = "⏪", + [":rhino:"] = "\uD83E\uDD8F", + [":rhinoceros:"] = "\uD83E\uDD8F", + [":ribbon:"] = "\uD83C\uDF80", + [":rice:"] = "\uD83C\uDF5A", + [":rice_ball:"] = "\uD83C\uDF59", + [":rice_cracker:"] = "\uD83C\uDF58", + [":rice_scene:"] = "\uD83C\uDF91", + [":right_anger_bubble:"] = "\uD83D\uDDEF️", + [":right_facing_fist:"] = "\uD83E\uDD1C", + [":right_facing_fist::skin-tone-1:"] = "\uD83E\uDD1C\uD83C\uDFFB", + [":right_facing_fist::skin-tone-2:"] = "\uD83E\uDD1C\uD83C\uDFFC", + [":right_facing_fist::skin-tone-3:"] = "\uD83E\uDD1C\uD83C\uDFFD", + [":right_facing_fist::skin-tone-4:"] = "\uD83E\uDD1C\uD83C\uDFFE", + [":right_facing_fist::skin-tone-5:"] = "\uD83E\uDD1C\uD83C\uDFFF", + [":right_facing_fist_tone1:"] = "\uD83E\uDD1C\uD83C\uDFFB", + [":right_facing_fist_tone2:"] = "\uD83E\uDD1C\uD83C\uDFFC", + [":right_facing_fist_tone3:"] = "\uD83E\uDD1C\uD83C\uDFFD", + [":right_facing_fist_tone4:"] = "\uD83E\uDD1C\uD83C\uDFFE", + [":right_facing_fist_tone5:"] = "\uD83E\uDD1C\uD83C\uDFFF", + [":right_fist:"] = "\uD83E\uDD1C", + [":right_fist::skin-tone-1:"] = "\uD83E\uDD1C\uD83C\uDFFB", + [":right_fist::skin-tone-2:"] = "\uD83E\uDD1C\uD83C\uDFFC", + [":right_fist::skin-tone-3:"] = "\uD83E\uDD1C\uD83C\uDFFD", + [":right_fist::skin-tone-4:"] = "\uD83E\uDD1C\uD83C\uDFFE", + [":right_fist::skin-tone-5:"] = "\uD83E\uDD1C\uD83C\uDFFF", + [":right_fist_tone1:"] = "\uD83E\uDD1C\uD83C\uDFFB", + [":right_fist_tone2:"] = "\uD83E\uDD1C\uD83C\uDFFC", + [":right_fist_tone3:"] = "\uD83E\uDD1C\uD83C\uDFFD", + [":right_fist_tone4:"] = "\uD83E\uDD1C\uD83C\uDFFE", + [":right_fist_tone5:"] = "\uD83E\uDD1C\uD83C\uDFFF", + [":ring:"] = "\uD83D\uDC8D", + [":ringed_planet:"] = "\uD83E\uDE90", + [":robot:"] = "\uD83E\uDD16", + [":robot_face:"] = "\uD83E\uDD16", + [":rocket:"] = "\uD83D\uDE80", + [":rofl:"] = "\uD83E\uDD23", + [":roll_of_paper:"] = "\uD83E\uDDFB", + [":rolled_up_newspaper:"] = "\uD83D\uDDDE️", + [":roller_coaster:"] = "\uD83C\uDFA2", + [":rolling_eyes:"] = "\uD83D\uDE44", + [":rolling_on_the_floor_laughing:"] = "\uD83E\uDD23", + [":rooster:"] = "\uD83D\uDC13", + [":rose:"] = "\uD83C\uDF39", + [":rosette:"] = "\uD83C\uDFF5️", + [":rotating_light:"] = "\uD83D\uDEA8", + [":round_pushpin:"] = "\uD83D\uDCCD", + [":rowboat:"] = "\uD83D\uDEA3", + [":rowboat::skin-tone-1:"] = "\uD83D\uDEA3\uD83C\uDFFB", + [":rowboat::skin-tone-2:"] = "\uD83D\uDEA3\uD83C\uDFFC", + [":rowboat::skin-tone-3:"] = "\uD83D\uDEA3\uD83C\uDFFD", + [":rowboat::skin-tone-4:"] = "\uD83D\uDEA3\uD83C\uDFFE", + [":rowboat::skin-tone-5:"] = "\uD83D\uDEA3\uD83C\uDFFF", + [":rowboat_tone1:"] = "\uD83D\uDEA3\uD83C\uDFFB", + [":rowboat_tone2:"] = "\uD83D\uDEA3\uD83C\uDFFC", + [":rowboat_tone3:"] = "\uD83D\uDEA3\uD83C\uDFFD", + [":rowboat_tone4:"] = "\uD83D\uDEA3\uD83C\uDFFE", + [":rowboat_tone5:"] = "\uD83D\uDEA3\uD83C\uDFFF", + [":rugby_football:"] = "\uD83C\uDFC9", + [":runner:"] = "\uD83C\uDFC3", + [":runner::skin-tone-1:"] = "\uD83C\uDFC3\uD83C\uDFFB", + [":runner::skin-tone-2:"] = "\uD83C\uDFC3\uD83C\uDFFC", + [":runner::skin-tone-3:"] = "\uD83C\uDFC3\uD83C\uDFFD", + [":runner::skin-tone-4:"] = "\uD83C\uDFC3\uD83C\uDFFE", + [":runner::skin-tone-5:"] = "\uD83C\uDFC3\uD83C\uDFFF", + [":runner_tone1:"] = "\uD83C\uDFC3\uD83C\uDFFB", + [":runner_tone2:"] = "\uD83C\uDFC3\uD83C\uDFFC", + [":runner_tone3:"] = "\uD83C\uDFC3\uD83C\uDFFD", + [":runner_tone4:"] = "\uD83C\uDFC3\uD83C\uDFFE", + [":runner_tone5:"] = "\uD83C\uDFC3\uD83C\uDFFF", + [":running_shirt_with_sash:"] = "\uD83C\uDFBD", + [":s"] = "\uD83D\uDE12", + [":sa:"] = "\uD83C\uDE02️", + [":safety_pin:"] = "\uD83E\uDDF7", + [":safety_vest:"] = "\uD83E\uDDBA", + [":sagittarius:"] = "♐", + [":sailboat:"] = "⛵", + [":sake:"] = "\uD83C\uDF76", + [":salad:"] = "\uD83E\uDD57", + [":salt:"] = "\uD83E\uDDC2", + [":sandal:"] = "\uD83D\uDC61", + [":sandwich:"] = "\uD83E\uDD6A", + [":santa:"] = "\uD83C\uDF85", + [":santa::skin-tone-1:"] = "\uD83C\uDF85\uD83C\uDFFB", + [":santa::skin-tone-2:"] = "\uD83C\uDF85\uD83C\uDFFC", + [":santa::skin-tone-3:"] = "\uD83C\uDF85\uD83C\uDFFD", + [":santa::skin-tone-4:"] = "\uD83C\uDF85\uD83C\uDFFE", + [":santa::skin-tone-5:"] = "\uD83C\uDF85\uD83C\uDFFF", + [":santa_tone1:"] = "\uD83C\uDF85\uD83C\uDFFB", + [":santa_tone2:"] = "\uD83C\uDF85\uD83C\uDFFC", + [":santa_tone3:"] = "\uD83C\uDF85\uD83C\uDFFD", + [":santa_tone4:"] = "\uD83C\uDF85\uD83C\uDFFE", + [":santa_tone5:"] = "\uD83C\uDF85\uD83C\uDFFF", + [":sari:"] = "\uD83E\uDD7B", + [":satellite:"] = "\uD83D\uDCE1", + [":satellite_orbital:"] = "\uD83D\uDEF0️", + [":satisfied:"] = "\uD83D\uDE06", + [":sauropod:"] = "\uD83E\uDD95", + [":saxophone:"] = "\uD83C\uDFB7", + [":scales:"] = "⚖️", + [":scarf:"] = "\uD83E\uDDE3", + [":school:"] = "\uD83C\uDFEB", + [":school_satchel:"] = "\uD83C\uDF92", + [":scissors:"] = "✂️", + [":scooter:"] = "\uD83D\uDEF4", + [":scorpion:"] = "\uD83E\uDD82", + [":scorpius:"] = "♏", + [":scotland:"] = "\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74\uDB40\uDC7F", + [":scream:"] = "\uD83D\uDE31", + [":scream_cat:"] = "\uD83D\uDE40", + [":scroll:"] = "\uD83D\uDCDC", + [":seat:"] = "\uD83D\uDCBA", + [":second_place:"] = "\uD83E\uDD48", + [":second_place_medal:"] = "\uD83E\uDD48", + [":secret:"] = "㊙️", + [":see_no_evil:"] = "\uD83D\uDE48", + [":seedling:"] = "\uD83C\uDF31", + [":selfie:"] = "\uD83E\uDD33", + [":selfie::skin-tone-1:"] = "\uD83E\uDD33\uD83C\uDFFB", + [":selfie::skin-tone-2:"] = "\uD83E\uDD33\uD83C\uDFFC", + [":selfie::skin-tone-3:"] = "\uD83E\uDD33\uD83C\uDFFD", + [":selfie::skin-tone-4:"] = "\uD83E\uDD33\uD83C\uDFFE", + [":selfie::skin-tone-5:"] = "\uD83E\uDD33\uD83C\uDFFF", + [":selfie_tone1:"] = "\uD83E\uDD33\uD83C\uDFFB", + [":selfie_tone2:"] = "\uD83E\uDD33\uD83C\uDFFC", + [":selfie_tone3:"] = "\uD83E\uDD33\uD83C\uDFFD", + [":selfie_tone4:"] = "\uD83E\uDD33\uD83C\uDFFE", + [":selfie_tone5:"] = "\uD83E\uDD33\uD83C\uDFFF", + [":service_dog:"] = "\uD83D\uDC15\u200D\uD83E\uDDBA", + [":seven:"] = "7️⃣", + [":shaking_hands:"] = "\uD83E\uDD1D", + [":shallow_pan_of_food:"] = "\uD83E\uDD58", + [":shamrock:"] = "☘️", + [":shark:"] = "\uD83E\uDD88", + [":shaved_ice:"] = "\uD83C\uDF67", + [":sheep:"] = "\uD83D\uDC11", + [":shell:"] = "\uD83D\uDC1A", + [":shelled_peanut:"] = "\uD83E\uDD5C", + [":shield:"] = "\uD83D\uDEE1️", + [":shinto_shrine:"] = "⛩️", + [":ship:"] = "\uD83D\uDEA2", + [":shirt:"] = "\uD83D\uDC55", + [":shit:"] = "\uD83D\uDCA9", + [":shopping_bags:"] = "\uD83D\uDECD️", + [":shopping_cart:"] = "\uD83D\uDED2", + [":shopping_trolley:"] = "\uD83D\uDED2", + [":shorts:"] = "\uD83E\uDE73", + [":shower:"] = "\uD83D\uDEBF", + [":shrimp:"] = "\uD83E\uDD90", + [":shrug:"] = "\uD83E\uDD37", + [":shrug::skin-tone-1:"] = "\uD83E\uDD37\uD83C\uDFFB", + [":shrug::skin-tone-2:"] = "\uD83E\uDD37\uD83C\uDFFC", + [":shrug::skin-tone-3:"] = "\uD83E\uDD37\uD83C\uDFFD", + [":shrug::skin-tone-4:"] = "\uD83E\uDD37\uD83C\uDFFE", + [":shrug::skin-tone-5:"] = "\uD83E\uDD37\uD83C\uDFFF", + [":shrug_tone1:"] = "\uD83E\uDD37\uD83C\uDFFB", + [":shrug_tone2:"] = "\uD83E\uDD37\uD83C\uDFFC", + [":shrug_tone3:"] = "\uD83E\uDD37\uD83C\uDFFD", + [":shrug_tone4:"] = "\uD83E\uDD37\uD83C\uDFFE", + [":shrug_tone5:"] = "\uD83E\uDD37\uD83C\uDFFF", + [":shushing_face:"] = "\uD83E\uDD2B", + [":sick:"] = "\uD83E\uDD22", + [":sign_of_the_horns:"] = "\uD83E\uDD18", + [":sign_of_the_horns::skin-tone-1:"] = "\uD83E\uDD18\uD83C\uDFFB", + [":sign_of_the_horns::skin-tone-2:"] = "\uD83E\uDD18\uD83C\uDFFC", + [":sign_of_the_horns::skin-tone-3:"] = "\uD83E\uDD18\uD83C\uDFFD", + [":sign_of_the_horns::skin-tone-4:"] = "\uD83E\uDD18\uD83C\uDFFE", + [":sign_of_the_horns::skin-tone-5:"] = "\uD83E\uDD18\uD83C\uDFFF", + [":sign_of_the_horns_tone1:"] = "\uD83E\uDD18\uD83C\uDFFB", + [":sign_of_the_horns_tone2:"] = "\uD83E\uDD18\uD83C\uDFFC", + [":sign_of_the_horns_tone3:"] = "\uD83E\uDD18\uD83C\uDFFD", + [":sign_of_the_horns_tone4:"] = "\uD83E\uDD18\uD83C\uDFFE", + [":sign_of_the_horns_tone5:"] = "\uD83E\uDD18\uD83C\uDFFF", + [":signal_strength:"] = "\uD83D\uDCF6", + [":six:"] = "6️⃣", + [":six_pointed_star:"] = "\uD83D\uDD2F", + [":skateboard:"] = "\uD83D\uDEF9", + [":skeleton:"] = "\uD83D\uDC80", + [":ski:"] = "\uD83C\uDFBF", + [":skier:"] = "⛷️", + [":skull:"] = "\uD83D\uDC80", + [":skull_and_crossbones:"] = "☠️", + [":skull_crossbones:"] = "☠️", + [":skunk:"] = "\uD83E\uDDA8", + [":sled:"] = "\uD83D\uDEF7", + [":sleeping:"] = "\uD83D\uDE34", + [":sleeping_accommodation:"] = "\uD83D\uDECC", + [":sleeping_accommodation::skin-tone-1:"] = "\uD83D\uDECC\uD83C\uDFFB", + [":sleeping_accommodation::skin-tone-2:"] = "\uD83D\uDECC\uD83C\uDFFC", + [":sleeping_accommodation::skin-tone-3:"] = "\uD83D\uDECC\uD83C\uDFFD", + [":sleeping_accommodation::skin-tone-4:"] = "\uD83D\uDECC\uD83C\uDFFE", + [":sleeping_accommodation::skin-tone-5:"] = "\uD83D\uDECC\uD83C\uDFFF", + [":sleepy:"] = "\uD83D\uDE2A", + [":sleuth_or_spy:"] = "\uD83D\uDD75️", + [":sleuth_or_spy::skin-tone-1:"] = "\uD83D\uDD75\uD83C\uDFFB", + [":sleuth_or_spy::skin-tone-2:"] = "\uD83D\uDD75\uD83C\uDFFC", + [":sleuth_or_spy::skin-tone-3:"] = "\uD83D\uDD75\uD83C\uDFFD", + [":sleuth_or_spy::skin-tone-4:"] = "\uD83D\uDD75\uD83C\uDFFE", + [":sleuth_or_spy::skin-tone-5:"] = "\uD83D\uDD75\uD83C\uDFFF", + [":sleuth_or_spy_tone1:"] = "\uD83D\uDD75\uD83C\uDFFB", + [":sleuth_or_spy_tone2:"] = "\uD83D\uDD75\uD83C\uDFFC", + [":sleuth_or_spy_tone3:"] = "\uD83D\uDD75\uD83C\uDFFD", + [":sleuth_or_spy_tone4:"] = "\uD83D\uDD75\uD83C\uDFFE", + [":sleuth_or_spy_tone5:"] = "\uD83D\uDD75\uD83C\uDFFF", + [":slight_frown:"] = "\uD83D\uDE41", + [":slight_smile:"] = "\uD83D\uDE42", + [":slightly_frowning_face:"] = "\uD83D\uDE41", + [":slightly_smiling_face:"] = "\uD83D\uDE42", + [":slot_machine:"] = "\uD83C\uDFB0", + [":sloth:"] = "\uD83E\uDDA5", + [":small_airplane:"] = "\uD83D\uDEE9️", + [":small_blue_diamond:"] = "\uD83D\uDD39", + [":small_orange_diamond:"] = "\uD83D\uDD38", + [":small_red_triangle:"] = "\uD83D\uDD3A", + [":small_red_triangle_down:"] = "\uD83D\uDD3B", + [":smile:"] = "\uD83D\uDE04", + [":smile_cat:"] = "\uD83D\uDE38", + [":smiley:"] = "\uD83D\uDE03", + [":smiley_cat:"] = "\uD83D\uDE3A", + [":smiling_face_with_3_hearts:"] = "\uD83E\uDD70", + [":smiling_imp:"] = "\uD83D\uDE08", + [":smirk:"] = "\uD83D\uDE0F", + [":smirk_cat:"] = "\uD83D\uDE3C", + [":smoking:"] = "\uD83D\uDEAC", + [":snail:"] = "\uD83D\uDC0C", + [":snake:"] = "\uD83D\uDC0D", + [":sneeze:"] = "\uD83E\uDD27", + [":sneezing_face:"] = "\uD83E\uDD27", + [":snow_capped_mountain:"] = "\uD83C\uDFD4️", + [":snowboarder:"] = "\uD83C\uDFC2", + [":snowboarder::skin-tone-1:"] = "\uD83C\uDFC2\uD83C\uDFFB", + [":snowboarder::skin-tone-2:"] = "\uD83C\uDFC2\uD83C\uDFFC", + [":snowboarder::skin-tone-3:"] = "\uD83C\uDFC2\uD83C\uDFFD", + [":snowboarder::skin-tone-4:"] = "\uD83C\uDFC2\uD83C\uDFFE", + [":snowboarder::skin-tone-5:"] = "\uD83C\uDFC2\uD83C\uDFFF", + [":snowboarder_dark_skin_tone:"] = "\uD83C\uDFC2\uD83C\uDFFF", + [":snowboarder_light_skin_tone:"] = "\uD83C\uDFC2\uD83C\uDFFB", + [":snowboarder_medium_dark_skin_tone:"] = "\uD83C\uDFC2\uD83C\uDFFE", + [":snowboarder_medium_light_skin_tone:"] = "\uD83C\uDFC2\uD83C\uDFFC", + [":snowboarder_medium_skin_tone:"] = "\uD83C\uDFC2\uD83C\uDFFD", + [":snowboarder_tone1:"] = "\uD83C\uDFC2\uD83C\uDFFB", + [":snowboarder_tone2:"] = "\uD83C\uDFC2\uD83C\uDFFC", + [":snowboarder_tone3:"] = "\uD83C\uDFC2\uD83C\uDFFD", + [":snowboarder_tone4:"] = "\uD83C\uDFC2\uD83C\uDFFE", + [":snowboarder_tone5:"] = "\uD83C\uDFC2\uD83C\uDFFF", + [":snowflake:"] = "❄️", + [":snowman2:"] = "☃️", + [":snowman:"] = "⛄", + [":soap:"] = "\uD83E\uDDFC", + [":sob:"] = "\uD83D\uDE2D", + [":soccer:"] = "⚽", + [":socks:"] = "\uD83E\uDDE6", + [":softball:"] = "\uD83E\uDD4E", + [":soon:"] = "\uD83D\uDD1C", + [":sos:"] = "\uD83C\uDD98", + [":sound:"] = "\uD83D\uDD09", + [":space_invader:"] = "\uD83D\uDC7E", + [":spades:"] = "♠️", + [":spaghetti:"] = "\uD83C\uDF5D", + [":sparkle:"] = "❇️", + [":sparkler:"] = "\uD83C\uDF87", + [":sparkles:"] = "✨", + [":sparkling_heart:"] = "\uD83D\uDC96", + [":speak_no_evil:"] = "\uD83D\uDE4A", + [":speaker:"] = "\uD83D\uDD08", + [":speaking_head:"] = "\uD83D\uDDE3️", + [":speaking_head_in_silhouette:"] = "\uD83D\uDDE3️", + [":speech_balloon:"] = "\uD83D\uDCAC", + [":speech_left:"] = "\uD83D\uDDE8️", + [":speedboat:"] = "\uD83D\uDEA4", + [":spider:"] = "\uD83D\uDD77️", + [":spider_web:"] = "\uD83D\uDD78️", + [":spiral_calendar_pad:"] = "\uD83D\uDDD3️", + [":spiral_note_pad:"] = "\uD83D\uDDD2️", + [":sponge:"] = "\uD83E\uDDFD", + [":spoon:"] = "\uD83E\uDD44", + [":sports_medal:"] = "\uD83C\uDFC5", + [":spy:"] = "\uD83D\uDD75️", + [":spy::skin-tone-1:"] = "\uD83D\uDD75\uD83C\uDFFB", + [":spy::skin-tone-2:"] = "\uD83D\uDD75\uD83C\uDFFC", + [":spy::skin-tone-3:"] = "\uD83D\uDD75\uD83C\uDFFD", + [":spy::skin-tone-4:"] = "\uD83D\uDD75\uD83C\uDFFE", + [":spy::skin-tone-5:"] = "\uD83D\uDD75\uD83C\uDFFF", + [":spy_tone1:"] = "\uD83D\uDD75\uD83C\uDFFB", + [":spy_tone2:"] = "\uD83D\uDD75\uD83C\uDFFC", + [":spy_tone3:"] = "\uD83D\uDD75\uD83C\uDFFD", + [":spy_tone4:"] = "\uD83D\uDD75\uD83C\uDFFE", + [":spy_tone5:"] = "\uD83D\uDD75\uD83C\uDFFF", + [":squeeze_bottle:"] = "\uD83E\uDDF4", + [":squid:"] = "\uD83E\uDD91", + [":stadium:"] = "\uD83C\uDFDF️", + [":star2:"] = "\uD83C\uDF1F", + [":star:"] = "⭐", + [":star_and_crescent:"] = "☪️", + [":star_of_david:"] = "✡️", + [":star_struck:"] = "\uD83E\uDD29", + [":stars:"] = "\uD83C\uDF20", + [":station:"] = "\uD83D\uDE89", + [":statue_of_liberty:"] = "\uD83D\uDDFD", + [":steam_locomotive:"] = "\uD83D\uDE82", + [":stethoscope:"] = "\uD83E\uDE7A", + [":stew:"] = "\uD83C\uDF72", + [":stop_button:"] = "⏹️", + [":stop_sign:"] = "\uD83D\uDED1", + [":stopwatch:"] = "⏱️", + [":straight_ruler:"] = "\uD83D\uDCCF", + [":strawberry:"] = "\uD83C\uDF53", + [":stuck_out_tongue:"] = "\uD83D\uDE1B", + [":stuck_out_tongue_closed_eyes:"] = "\uD83D\uDE1D", + [":stuck_out_tongue_winking_eye:"] = "\uD83D\uDE1C", + [":studio_microphone:"] = "\uD83C\uDF99️", + [":stuffed_flatbread:"] = "\uD83E\uDD59", + [":stuffed_pita:"] = "\uD83E\uDD59", + [":sun_with_face:"] = "\uD83C\uDF1E", + [":sunflower:"] = "\uD83C\uDF3B", + [":sunglasses:"] = "\uD83D\uDE0E", + [":sunny:"] = "☀️", + [":sunrise:"] = "\uD83C\uDF05", + [":sunrise_over_mountains:"] = "\uD83C\uDF04", + [":superhero:"] = "\uD83E\uDDB8", + [":superhero::skin-tone-1:"] = "\uD83E\uDDB8\uD83C\uDFFB", + [":superhero::skin-tone-2:"] = "\uD83E\uDDB8\uD83C\uDFFC", + [":superhero::skin-tone-3:"] = "\uD83E\uDDB8\uD83C\uDFFD", + [":superhero::skin-tone-4:"] = "\uD83E\uDDB8\uD83C\uDFFE", + [":superhero::skin-tone-5:"] = "\uD83E\uDDB8\uD83C\uDFFF", + [":superhero_dark_skin_tone:"] = "\uD83E\uDDB8\uD83C\uDFFF", + [":superhero_light_skin_tone:"] = "\uD83E\uDDB8\uD83C\uDFFB", + [":superhero_medium_dark_skin_tone:"] = "\uD83E\uDDB8\uD83C\uDFFE", + [":superhero_medium_light_skin_tone:"] = "\uD83E\uDDB8\uD83C\uDFFC", + [":superhero_medium_skin_tone:"] = "\uD83E\uDDB8\uD83C\uDFFD", + [":superhero_tone1:"] = "\uD83E\uDDB8\uD83C\uDFFB", + [":superhero_tone2:"] = "\uD83E\uDDB8\uD83C\uDFFC", + [":superhero_tone3:"] = "\uD83E\uDDB8\uD83C\uDFFD", + [":superhero_tone4:"] = "\uD83E\uDDB8\uD83C\uDFFE", + [":superhero_tone5:"] = "\uD83E\uDDB8\uD83C\uDFFF", + [":supervillain:"] = "\uD83E\uDDB9", + [":supervillain::skin-tone-1:"] = "\uD83E\uDDB9\uD83C\uDFFB", + [":supervillain::skin-tone-2:"] = "\uD83E\uDDB9\uD83C\uDFFC", + [":supervillain::skin-tone-3:"] = "\uD83E\uDDB9\uD83C\uDFFD", + [":supervillain::skin-tone-4:"] = "\uD83E\uDDB9\uD83C\uDFFE", + [":supervillain::skin-tone-5:"] = "\uD83E\uDDB9\uD83C\uDFFF", + [":supervillain_dark_skin_tone:"] = "\uD83E\uDDB9\uD83C\uDFFF", + [":supervillain_light_skin_tone:"] = "\uD83E\uDDB9\uD83C\uDFFB", + [":supervillain_medium_dark_skin_tone:"] = "\uD83E\uDDB9\uD83C\uDFFE", + [":supervillain_medium_light_skin_tone:"] = "\uD83E\uDDB9\uD83C\uDFFC", + [":supervillain_medium_skin_tone:"] = "\uD83E\uDDB9\uD83C\uDFFD", + [":supervillain_tone1:"] = "\uD83E\uDDB9\uD83C\uDFFB", + [":supervillain_tone2:"] = "\uD83E\uDDB9\uD83C\uDFFC", + [":supervillain_tone3:"] = "\uD83E\uDDB9\uD83C\uDFFD", + [":supervillain_tone4:"] = "\uD83E\uDDB9\uD83C\uDFFE", + [":supervillain_tone5:"] = "\uD83E\uDDB9\uD83C\uDFFF", + [":surfer:"] = "\uD83C\uDFC4", + [":surfer::skin-tone-1:"] = "\uD83C\uDFC4\uD83C\uDFFB", + [":surfer::skin-tone-2:"] = "\uD83C\uDFC4\uD83C\uDFFC", + [":surfer::skin-tone-3:"] = "\uD83C\uDFC4\uD83C\uDFFD", + [":surfer::skin-tone-4:"] = "\uD83C\uDFC4\uD83C\uDFFE", + [":surfer::skin-tone-5:"] = "\uD83C\uDFC4\uD83C\uDFFF", + [":surfer_tone1:"] = "\uD83C\uDFC4\uD83C\uDFFB", + [":surfer_tone2:"] = "\uD83C\uDFC4\uD83C\uDFFC", + [":surfer_tone3:"] = "\uD83C\uDFC4\uD83C\uDFFD", + [":surfer_tone4:"] = "\uD83C\uDFC4\uD83C\uDFFE", + [":surfer_tone5:"] = "\uD83C\uDFC4\uD83C\uDFFF", + [":sushi:"] = "\uD83C\uDF63", + [":suspension_railway:"] = "\uD83D\uDE9F", + [":swan:"] = "\uD83E\uDDA2", + [":sweat:"] = "\uD83D\uDE13", + [":sweat_drops:"] = "\uD83D\uDCA6", + [":sweat_smile:"] = "\uD83D\uDE05", + [":sweet_potato:"] = "\uD83C\uDF60", + [":swimmer:"] = "\uD83C\uDFCA", + [":swimmer::skin-tone-1:"] = "\uD83C\uDFCA\uD83C\uDFFB", + [":swimmer::skin-tone-2:"] = "\uD83C\uDFCA\uD83C\uDFFC", + [":swimmer::skin-tone-3:"] = "\uD83C\uDFCA\uD83C\uDFFD", + [":swimmer::skin-tone-4:"] = "\uD83C\uDFCA\uD83C\uDFFE", + [":swimmer::skin-tone-5:"] = "\uD83C\uDFCA\uD83C\uDFFF", + [":swimmer_tone1:"] = "\uD83C\uDFCA\uD83C\uDFFB", + [":swimmer_tone2:"] = "\uD83C\uDFCA\uD83C\uDFFC", + [":swimmer_tone3:"] = "\uD83C\uDFCA\uD83C\uDFFD", + [":swimmer_tone4:"] = "\uD83C\uDFCA\uD83C\uDFFE", + [":swimmer_tone5:"] = "\uD83C\uDFCA\uD83C\uDFFF", + [":symbols:"] = "\uD83D\uDD23", + [":synagogue:"] = "\uD83D\uDD4D", + [":syringe:"] = "\uD83D\uDC89", + [":t_rex:"] = "\uD83E\uDD96", + [":table_tennis:"] = "\uD83C\uDFD3", + [":taco:"] = "\uD83C\uDF2E", + [":tada:"] = "\uD83C\uDF89", + [":takeout_box:"] = "\uD83E\uDD61", + [":tanabata_tree:"] = "\uD83C\uDF8B", + [":tangerine:"] = "\uD83C\uDF4A", + [":taurus:"] = "♉", + [":taxi:"] = "\uD83D\uDE95", + [":tea:"] = "\uD83C\uDF75", + [":teddy_bear:"] = "\uD83E\uDDF8", + [":telephone:"] = "☎️", + [":telephone_receiver:"] = "\uD83D\uDCDE", + [":telescope:"] = "\uD83D\uDD2D", + [":tennis:"] = "\uD83C\uDFBE", + [":tent:"] = "⛺", + [":test_tube:"] = "\uD83E\uDDEA", + [":thermometer:"] = "\uD83C\uDF21️", + [":thermometer_face:"] = "\uD83E\uDD12", + [":thinking:"] = "\uD83E\uDD14", + [":thinking_face:"] = "\uD83E\uDD14", + [":third_place:"] = "\uD83E\uDD49", + [":third_place_medal:"] = "\uD83E\uDD49", + [":thought_balloon:"] = "\uD83D\uDCAD", + [":thread:"] = "\uD83E\uDDF5", + [":three:"] = "3️⃣", + [":three_button_mouse:"] = "\uD83D\uDDB1️", + [":thumbdown:"] = "\uD83D\uDC4E", + [":thumbdown::skin-tone-1:"] = "\uD83D\uDC4E\uD83C\uDFFB", + [":thumbdown::skin-tone-2:"] = "\uD83D\uDC4E\uD83C\uDFFC", + [":thumbdown::skin-tone-3:"] = "\uD83D\uDC4E\uD83C\uDFFD", + [":thumbdown::skin-tone-4:"] = "\uD83D\uDC4E\uD83C\uDFFE", + [":thumbdown::skin-tone-5:"] = "\uD83D\uDC4E\uD83C\uDFFF", + [":thumbdown_tone1:"] = "\uD83D\uDC4E\uD83C\uDFFB", + [":thumbdown_tone2:"] = "\uD83D\uDC4E\uD83C\uDFFC", + [":thumbdown_tone3:"] = "\uD83D\uDC4E\uD83C\uDFFD", + [":thumbdown_tone4:"] = "\uD83D\uDC4E\uD83C\uDFFE", + [":thumbdown_tone5:"] = "\uD83D\uDC4E\uD83C\uDFFF", + [":thumbsdown:"] = "\uD83D\uDC4E", + [":thumbsdown::skin-tone-1:"] = "\uD83D\uDC4E\uD83C\uDFFB", + [":thumbsdown::skin-tone-2:"] = "\uD83D\uDC4E\uD83C\uDFFC", + [":thumbsdown::skin-tone-3:"] = "\uD83D\uDC4E\uD83C\uDFFD", + [":thumbsdown::skin-tone-4:"] = "\uD83D\uDC4E\uD83C\uDFFE", + [":thumbsdown::skin-tone-5:"] = "\uD83D\uDC4E\uD83C\uDFFF", + [":thumbsdown_tone1:"] = "\uD83D\uDC4E\uD83C\uDFFB", + [":thumbsdown_tone2:"] = "\uD83D\uDC4E\uD83C\uDFFC", + [":thumbsdown_tone3:"] = "\uD83D\uDC4E\uD83C\uDFFD", + [":thumbsdown_tone4:"] = "\uD83D\uDC4E\uD83C\uDFFE", + [":thumbsdown_tone5:"] = "\uD83D\uDC4E\uD83C\uDFFF", + [":thumbsup:"] = "\uD83D\uDC4D", + [":thumbsup::skin-tone-1:"] = "\uD83D\uDC4D\uD83C\uDFFB", + [":thumbsup::skin-tone-2:"] = "\uD83D\uDC4D\uD83C\uDFFC", + [":thumbsup::skin-tone-3:"] = "\uD83D\uDC4D\uD83C\uDFFD", + [":thumbsup::skin-tone-4:"] = "\uD83D\uDC4D\uD83C\uDFFE", + [":thumbsup::skin-tone-5:"] = "\uD83D\uDC4D\uD83C\uDFFF", + [":thumbsup_tone1:"] = "\uD83D\uDC4D\uD83C\uDFFB", + [":thumbsup_tone2:"] = "\uD83D\uDC4D\uD83C\uDFFC", + [":thumbsup_tone3:"] = "\uD83D\uDC4D\uD83C\uDFFD", + [":thumbsup_tone4:"] = "\uD83D\uDC4D\uD83C\uDFFE", + [":thumbsup_tone5:"] = "\uD83D\uDC4D\uD83C\uDFFF", + [":thumbup:"] = "\uD83D\uDC4D", + [":thumbup::skin-tone-1:"] = "\uD83D\uDC4D\uD83C\uDFFB", + [":thumbup::skin-tone-2:"] = "\uD83D\uDC4D\uD83C\uDFFC", + [":thumbup::skin-tone-3:"] = "\uD83D\uDC4D\uD83C\uDFFD", + [":thumbup::skin-tone-4:"] = "\uD83D\uDC4D\uD83C\uDFFE", + [":thumbup::skin-tone-5:"] = "\uD83D\uDC4D\uD83C\uDFFF", + [":thumbup_tone1:"] = "\uD83D\uDC4D\uD83C\uDFFB", + [":thumbup_tone2:"] = "\uD83D\uDC4D\uD83C\uDFFC", + [":thumbup_tone3:"] = "\uD83D\uDC4D\uD83C\uDFFD", + [":thumbup_tone4:"] = "\uD83D\uDC4D\uD83C\uDFFE", + [":thumbup_tone5:"] = "\uD83D\uDC4D\uD83C\uDFFF", + [":thunder_cloud_and_rain:"] = "⛈️", + [":thunder_cloud_rain:"] = "⛈️", + [":ticket:"] = "\uD83C\uDFAB", + [":tickets:"] = "\uD83C\uDF9F️", + [":tiger2:"] = "\uD83D\uDC05", + [":tiger:"] = "\uD83D\uDC2F", + [":timer:"] = "⏲️", + [":timer_clock:"] = "⏲️", + [":tired_face:"] = "\uD83D\uDE2B", + [":tm:"] = "™️", + [":toilet:"] = "\uD83D\uDEBD", + [":tokyo_tower:"] = "\uD83D\uDDFC", + [":tomato:"] = "\uD83C\uDF45", + [":tongue:"] = "\uD83D\uDC45", + [":toolbox:"] = "\uD83E\uDDF0", + [":tools:"] = "\uD83D\uDEE0️", + [":tooth:"] = "\uD83E\uDDB7", + [":top:"] = "\uD83D\uDD1D", + [":tophat:"] = "\uD83C\uDFA9", + [":track_next:"] = "⏭️", + [":track_previous:"] = "⏮️", + [":trackball:"] = "\uD83D\uDDB2️", + [":tractor:"] = "\uD83D\uDE9C", + [":traffic_light:"] = "\uD83D\uDEA5", + [":train2:"] = "\uD83D\uDE86", + [":train:"] = "\uD83D\uDE8B", + [":tram:"] = "\uD83D\uDE8A", + [":triangular_flag_on_post:"] = "\uD83D\uDEA9", + [":triangular_ruler:"] = "\uD83D\uDCD0", + [":trident:"] = "\uD83D\uDD31", + [":triumph:"] = "\uD83D\uDE24", + [":trolleybus:"] = "\uD83D\uDE8E", + [":trophy:"] = "\uD83C\uDFC6", + [":tropical_drink:"] = "\uD83C\uDF79", + [":tropical_fish:"] = "\uD83D\uDC20", + [":truck:"] = "\uD83D\uDE9A", + [":trumpet:"] = "\uD83C\uDFBA", + [":tulip:"] = "\uD83C\uDF37", + [":tumbler_glass:"] = "\uD83E\uDD43", + [":turkey:"] = "\uD83E\uDD83", + [":turtle:"] = "\uD83D\uDC22", + [":tuxedo_tone1:"] = "\uD83E\uDD35\uD83C\uDFFB", + [":tuxedo_tone2:"] = "\uD83E\uDD35\uD83C\uDFFC", + [":tuxedo_tone3:"] = "\uD83E\uDD35\uD83C\uDFFD", + [":tuxedo_tone4:"] = "\uD83E\uDD35\uD83C\uDFFE", + [":tuxedo_tone5:"] = "\uD83E\uDD35\uD83C\uDFFF", + [":tv:"] = "\uD83D\uDCFA", + [":twisted_rightwards_arrows:"] = "\uD83D\uDD00", + [":two:"] = "2️⃣", + [":two_hearts:"] = "\uD83D\uDC95", + [":two_men_holding_hands:"] = "\uD83D\uDC6C", + [":two_women_holding_hands:"] = "\uD83D\uDC6D", + [":u5272:"] = "\uD83C\uDE39", + [":u5408:"] = "\uD83C\uDE34", + [":u55b6:"] = "\uD83C\uDE3A", + [":u6307:"] = "\uD83C\uDE2F", + [":u6708:"] = "\uD83C\uDE37️", + [":u6709:"] = "\uD83C\uDE36", + [":u6e80:"] = "\uD83C\uDE35", + [":u7121:"] = "\uD83C\uDE1A", + [":u7533:"] = "\uD83C\uDE38", + [":u7981:"] = "\uD83C\uDE32", + [":u7a7a:"] = "\uD83C\uDE33", + [":umbrella2:"] = "☂️", + [":umbrella:"] = "☔", + [":umbrella_on_ground:"] = "⛱️", + [":unamused:"] = "\uD83D\uDE12", + [":underage:"] = "\uD83D\uDD1E", + [":unicorn:"] = "\uD83E\uDD84", + [":unicorn_face:"] = "\uD83E\uDD84", + [":united_nations:"] = "\uD83C\uDDFA\uD83C\uDDF3", + [":unlock:"] = "\uD83D\uDD13", + [":up:"] = "\uD83C\uDD99", + [":upside_down:"] = "\uD83D\uDE43", + [":upside_down_face:"] = "\uD83D\uDE43", + [":urn:"] = "⚱️", + [":v:"] = "✌️", + [":v::skin-tone-1:"] = "✌\uD83C\uDFFB", + [":v::skin-tone-2:"] = "✌\uD83C\uDFFC", + [":v::skin-tone-3:"] = "✌\uD83C\uDFFD", + [":v::skin-tone-4:"] = "✌\uD83C\uDFFE", + [":v::skin-tone-5:"] = "✌\uD83C\uDFFF", + [":v_tone1:"] = "✌\uD83C\uDFFB", + [":v_tone2:"] = "✌\uD83C\uDFFC", + [":v_tone3:"] = "✌\uD83C\uDFFD", + [":v_tone4:"] = "✌\uD83C\uDFFE", + [":v_tone5:"] = "✌\uD83C\uDFFF", + [":vampire:"] = "\uD83E\uDDDB", + [":vampire::skin-tone-1:"] = "\uD83E\uDDDB\uD83C\uDFFB", + [":vampire::skin-tone-2:"] = "\uD83E\uDDDB\uD83C\uDFFC", + [":vampire::skin-tone-3:"] = "\uD83E\uDDDB\uD83C\uDFFD", + [":vampire::skin-tone-4:"] = "\uD83E\uDDDB\uD83C\uDFFE", + [":vampire::skin-tone-5:"] = "\uD83E\uDDDB\uD83C\uDFFF", + [":vampire_dark_skin_tone:"] = "\uD83E\uDDDB\uD83C\uDFFF", + [":vampire_light_skin_tone:"] = "\uD83E\uDDDB\uD83C\uDFFB", + [":vampire_medium_dark_skin_tone:"] = "\uD83E\uDDDB\uD83C\uDFFE", + [":vampire_medium_light_skin_tone:"] = "\uD83E\uDDDB\uD83C\uDFFC", + [":vampire_medium_skin_tone:"] = "\uD83E\uDDDB\uD83C\uDFFD", + [":vampire_tone1:"] = "\uD83E\uDDDB\uD83C\uDFFB", + [":vampire_tone2:"] = "\uD83E\uDDDB\uD83C\uDFFC", + [":vampire_tone3:"] = "\uD83E\uDDDB\uD83C\uDFFD", + [":vampire_tone4:"] = "\uD83E\uDDDB\uD83C\uDFFE", + [":vampire_tone5:"] = "\uD83E\uDDDB\uD83C\uDFFF", + [":vertical_traffic_light:"] = "\uD83D\uDEA6", + [":vhs:"] = "\uD83D\uDCFC", + [":vibration_mode:"] = "\uD83D\uDCF3", + [":video_camera:"] = "\uD83D\uDCF9", + [":video_game:"] = "\uD83C\uDFAE", + [":violin:"] = "\uD83C\uDFBB", + [":virgo:"] = "♍", + [":volcano:"] = "\uD83C\uDF0B", + [":volleyball:"] = "\uD83C\uDFD0", + [":vs:"] = "\uD83C\uDD9A", + [":vulcan:"] = "\uD83D\uDD96", + [":vulcan::skin-tone-1:"] = "\uD83D\uDD96\uD83C\uDFFB", + [":vulcan::skin-tone-2:"] = "\uD83D\uDD96\uD83C\uDFFC", + [":vulcan::skin-tone-3:"] = "\uD83D\uDD96\uD83C\uDFFD", + [":vulcan::skin-tone-4:"] = "\uD83D\uDD96\uD83C\uDFFE", + [":vulcan::skin-tone-5:"] = "\uD83D\uDD96\uD83C\uDFFF", + [":vulcan_tone1:"] = "\uD83D\uDD96\uD83C\uDFFB", + [":vulcan_tone2:"] = "\uD83D\uDD96\uD83C\uDFFC", + [":vulcan_tone3:"] = "\uD83D\uDD96\uD83C\uDFFD", + [":vulcan_tone4:"] = "\uD83D\uDD96\uD83C\uDFFE", + [":vulcan_tone5:"] = "\uD83D\uDD96\uD83C\uDFFF", + [":waffle:"] = "\uD83E\uDDC7", + [":wales:"] = "\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73\uDB40\uDC7F", + [":walking:"] = "\uD83D\uDEB6", + [":walking::skin-tone-1:"] = "\uD83D\uDEB6\uD83C\uDFFB", + [":walking::skin-tone-2:"] = "\uD83D\uDEB6\uD83C\uDFFC", + [":walking::skin-tone-3:"] = "\uD83D\uDEB6\uD83C\uDFFD", + [":walking::skin-tone-4:"] = "\uD83D\uDEB6\uD83C\uDFFE", + [":walking::skin-tone-5:"] = "\uD83D\uDEB6\uD83C\uDFFF", + [":walking_tone1:"] = "\uD83D\uDEB6\uD83C\uDFFB", + [":walking_tone2:"] = "\uD83D\uDEB6\uD83C\uDFFC", + [":walking_tone3:"] = "\uD83D\uDEB6\uD83C\uDFFD", + [":walking_tone4:"] = "\uD83D\uDEB6\uD83C\uDFFE", + [":walking_tone5:"] = "\uD83D\uDEB6\uD83C\uDFFF", + [":waning_crescent_moon:"] = "\uD83C\uDF18", + [":waning_gibbous_moon:"] = "\uD83C\uDF16", + [":warning:"] = "⚠️", + [":wastebasket:"] = "\uD83D\uDDD1️", + [":watch:"] = "⌚", + [":water_buffalo:"] = "\uD83D\uDC03", + [":water_polo:"] = "\uD83E\uDD3D", + [":water_polo::skin-tone-1:"] = "\uD83E\uDD3D\uD83C\uDFFB", + [":water_polo::skin-tone-2:"] = "\uD83E\uDD3D\uD83C\uDFFC", + [":water_polo::skin-tone-3:"] = "\uD83E\uDD3D\uD83C\uDFFD", + [":water_polo::skin-tone-4:"] = "\uD83E\uDD3D\uD83C\uDFFE", + [":water_polo::skin-tone-5:"] = "\uD83E\uDD3D\uD83C\uDFFF", + [":water_polo_tone1:"] = "\uD83E\uDD3D\uD83C\uDFFB", + [":water_polo_tone2:"] = "\uD83E\uDD3D\uD83C\uDFFC", + [":water_polo_tone3:"] = "\uD83E\uDD3D\uD83C\uDFFD", + [":water_polo_tone4:"] = "\uD83E\uDD3D\uD83C\uDFFE", + [":water_polo_tone5:"] = "\uD83E\uDD3D\uD83C\uDFFF", + [":watermelon:"] = "\uD83C\uDF49", + [":wave:"] = "\uD83D\uDC4B", + [":wave::skin-tone-1:"] = "\uD83D\uDC4B\uD83C\uDFFB", + [":wave::skin-tone-2:"] = "\uD83D\uDC4B\uD83C\uDFFC", + [":wave::skin-tone-3:"] = "\uD83D\uDC4B\uD83C\uDFFD", + [":wave::skin-tone-4:"] = "\uD83D\uDC4B\uD83C\uDFFE", + [":wave::skin-tone-5:"] = "\uD83D\uDC4B\uD83C\uDFFF", + [":wave_tone1:"] = "\uD83D\uDC4B\uD83C\uDFFB", + [":wave_tone2:"] = "\uD83D\uDC4B\uD83C\uDFFC", + [":wave_tone3:"] = "\uD83D\uDC4B\uD83C\uDFFD", + [":wave_tone4:"] = "\uD83D\uDC4B\uD83C\uDFFE", + [":wave_tone5:"] = "\uD83D\uDC4B\uD83C\uDFFF", + [":wavy_dash:"] = "〰️", + [":waxing_crescent_moon:"] = "\uD83C\uDF12", + [":waxing_gibbous_moon:"] = "\uD83C\uDF14", + [":wc:"] = "\uD83D\uDEBE", + [":weary:"] = "\uD83D\uDE29", + [":wedding:"] = "\uD83D\uDC92", + [":weight_lifter:"] = "\uD83C\uDFCB️", + [":weight_lifter::skin-tone-1:"] = "\uD83C\uDFCB\uD83C\uDFFB", + [":weight_lifter::skin-tone-2:"] = "\uD83C\uDFCB\uD83C\uDFFC", + [":weight_lifter::skin-tone-3:"] = "\uD83C\uDFCB\uD83C\uDFFD", + [":weight_lifter::skin-tone-4:"] = "\uD83C\uDFCB\uD83C\uDFFE", + [":weight_lifter::skin-tone-5:"] = "\uD83C\uDFCB\uD83C\uDFFF", + [":weight_lifter_tone1:"] = "\uD83C\uDFCB\uD83C\uDFFB", + [":weight_lifter_tone2:"] = "\uD83C\uDFCB\uD83C\uDFFC", + [":weight_lifter_tone3:"] = "\uD83C\uDFCB\uD83C\uDFFD", + [":weight_lifter_tone4:"] = "\uD83C\uDFCB\uD83C\uDFFE", + [":weight_lifter_tone5:"] = "\uD83C\uDFCB\uD83C\uDFFF", + [":whale2:"] = "\uD83D\uDC0B", + [":whale:"] = "\uD83D\uDC33", + [":wheel_of_dharma:"] = "☸️", + [":wheelchair:"] = "♿", + [":whisky:"] = "\uD83E\uDD43", + [":white_check_mark:"] = "✅", + [":white_circle:"] = "⚪", + [":white_flower:"] = "\uD83D\uDCAE", + [":white_frowning_face:"] = "☹️", + [":white_heart:"] = "\uD83E\uDD0D", + [":white_large_square:"] = "⬜", + [":white_medium_small_square:"] = "◽", + [":white_medium_square:"] = "◻️", + [":white_small_square:"] = "▫️", + [":white_square_button:"] = "\uD83D\uDD33", + [":white_sun_behind_cloud:"] = "\uD83C\uDF25️", + [":white_sun_behind_cloud_with_rain:"] = "\uD83C\uDF26️", + [":white_sun_cloud:"] = "\uD83C\uDF25️", + [":white_sun_rain_cloud:"] = "\uD83C\uDF26️", + [":white_sun_small_cloud:"] = "\uD83C\uDF24️", + [":white_sun_with_small_cloud:"] = "\uD83C\uDF24️", + [":wilted_flower:"] = "\uD83E\uDD40", + [":wilted_rose:"] = "\uD83E\uDD40", + [":wind_blowing_face:"] = "\uD83C\uDF2C️", + [":wind_chime:"] = "\uD83C\uDF90", + [":wine_glass:"] = "\uD83C\uDF77", + [":wink:"] = "\uD83D\uDE09", + [":wolf:"] = "\uD83D\uDC3A", + [":woman:"] = "\uD83D\uDC69", + [":woman::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB", + [":woman::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC", + [":woman::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD", + [":woman::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE", + [":woman::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF", + [":woman_artist:"] = "\uD83D\uDC69\u200D\uD83C\uDFA8", + [":woman_artist::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDFA8", + [":woman_artist::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDFA8", + [":woman_artist::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDFA8", + [":woman_artist::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDFA8", + [":woman_artist::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDFA8", + [":woman_artist_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDFA8", + [":woman_artist_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDFA8", + [":woman_artist_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDFA8", + [":woman_artist_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDFA8", + [":woman_artist_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDFA8", + [":woman_artist_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDFA8", + [":woman_artist_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDFA8", + [":woman_artist_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDFA8", + [":woman_artist_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDFA8", + [":woman_artist_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDFA8", + [":woman_astronaut:"] = "\uD83D\uDC69\u200D\uD83D\uDE80", + [":woman_astronaut::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDE80", + [":woman_astronaut::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDE80", + [":woman_astronaut::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDE80", + [":woman_astronaut::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDE80", + [":woman_astronaut::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDE80", + [":woman_astronaut_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDE80", + [":woman_astronaut_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDE80", + [":woman_astronaut_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDE80", + [":woman_astronaut_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDE80", + [":woman_astronaut_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDE80", + [":woman_astronaut_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDE80", + [":woman_astronaut_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDE80", + [":woman_astronaut_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDE80", + [":woman_astronaut_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDE80", + [":woman_astronaut_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDE80", + [":woman_bald:"] = "\uD83D\uDC69\u200D\uD83E\uDDB2", + [":woman_bald::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDB2", + [":woman_bald::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDB2", + [":woman_bald::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDB2", + [":woman_bald::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDB2", + [":woman_bald::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDB2", + [":woman_bald_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDB2", + [":woman_bald_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDB2", + [":woman_bald_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDB2", + [":woman_bald_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDB2", + [":woman_bald_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDB2", + [":woman_bald_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDB2", + [":woman_bald_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDB2", + [":woman_bald_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDB2", + [":woman_bald_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDB2", + [":woman_bald_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDB2", + [":woman_biking:"] = "\uD83D\uDEB4\u200D♀️", + [":woman_biking::skin-tone-1:"] = "\uD83D\uDEB4\uD83C\uDFFB\u200D♀️", + [":woman_biking::skin-tone-2:"] = "\uD83D\uDEB4\uD83C\uDFFC\u200D♀️", + [":woman_biking::skin-tone-3:"] = "\uD83D\uDEB4\uD83C\uDFFD\u200D♀️", + [":woman_biking::skin-tone-4:"] = "\uD83D\uDEB4\uD83C\uDFFE\u200D♀️", + [":woman_biking::skin-tone-5:"] = "\uD83D\uDEB4\uD83C\uDFFF\u200D♀️", + [":woman_biking_dark_skin_tone:"] = "\uD83D\uDEB4\uD83C\uDFFF\u200D♀️", + [":woman_biking_light_skin_tone:"] = "\uD83D\uDEB4\uD83C\uDFFB\u200D♀️", + [":woman_biking_medium_dark_skin_tone:"] = "\uD83D\uDEB4\uD83C\uDFFE\u200D♀️", + [":woman_biking_medium_light_skin_tone:"] = "\uD83D\uDEB4\uD83C\uDFFC\u200D♀️", + [":woman_biking_medium_skin_tone:"] = "\uD83D\uDEB4\uD83C\uDFFD\u200D♀️", + [":woman_biking_tone1:"] = "\uD83D\uDEB4\uD83C\uDFFB\u200D♀️", + [":woman_biking_tone2:"] = "\uD83D\uDEB4\uD83C\uDFFC\u200D♀️", + [":woman_biking_tone3:"] = "\uD83D\uDEB4\uD83C\uDFFD\u200D♀️", + [":woman_biking_tone4:"] = "\uD83D\uDEB4\uD83C\uDFFE\u200D♀️", + [":woman_biking_tone5:"] = "\uD83D\uDEB4\uD83C\uDFFF\u200D♀️", + [":woman_bouncing_ball:"] = "⛹️\u200D♀️", + [":woman_bouncing_ball::skin-tone-1:"] = "⛹\uD83C\uDFFB\u200D♀️", + [":woman_bouncing_ball::skin-tone-2:"] = "⛹\uD83C\uDFFC\u200D♀️", + [":woman_bouncing_ball::skin-tone-3:"] = "⛹\uD83C\uDFFD\u200D♀️", + [":woman_bouncing_ball::skin-tone-4:"] = "⛹\uD83C\uDFFE\u200D♀️", + [":woman_bouncing_ball::skin-tone-5:"] = "⛹\uD83C\uDFFF\u200D♀️", + [":woman_bouncing_ball_dark_skin_tone:"] = "⛹\uD83C\uDFFF\u200D♀️", + [":woman_bouncing_ball_light_skin_tone:"] = "⛹\uD83C\uDFFB\u200D♀️", + [":woman_bouncing_ball_medium_dark_skin_tone:"] = "⛹\uD83C\uDFFE\u200D♀️", + [":woman_bouncing_ball_medium_light_skin_tone:"] = "⛹\uD83C\uDFFC\u200D♀️", + [":woman_bouncing_ball_medium_skin_tone:"] = "⛹\uD83C\uDFFD\u200D♀️", + [":woman_bouncing_ball_tone1:"] = "⛹\uD83C\uDFFB\u200D♀️", + [":woman_bouncing_ball_tone2:"] = "⛹\uD83C\uDFFC\u200D♀️", + [":woman_bouncing_ball_tone3:"] = "⛹\uD83C\uDFFD\u200D♀️", + [":woman_bouncing_ball_tone4:"] = "⛹\uD83C\uDFFE\u200D♀️", + [":woman_bouncing_ball_tone5:"] = "⛹\uD83C\uDFFF\u200D♀️", + [":woman_bowing:"] = "\uD83D\uDE47\u200D♀️", + [":woman_bowing::skin-tone-1:"] = "\uD83D\uDE47\uD83C\uDFFB\u200D♀️", + [":woman_bowing::skin-tone-2:"] = "\uD83D\uDE47\uD83C\uDFFC\u200D♀️", + [":woman_bowing::skin-tone-3:"] = "\uD83D\uDE47\uD83C\uDFFD\u200D♀️", + [":woman_bowing::skin-tone-4:"] = "\uD83D\uDE47\uD83C\uDFFE\u200D♀️", + [":woman_bowing::skin-tone-5:"] = "\uD83D\uDE47\uD83C\uDFFF\u200D♀️", + [":woman_bowing_dark_skin_tone:"] = "\uD83D\uDE47\uD83C\uDFFF\u200D♀️", + [":woman_bowing_light_skin_tone:"] = "\uD83D\uDE47\uD83C\uDFFB\u200D♀️", + [":woman_bowing_medium_dark_skin_tone:"] = "\uD83D\uDE47\uD83C\uDFFE\u200D♀️", + [":woman_bowing_medium_light_skin_tone:"] = "\uD83D\uDE47\uD83C\uDFFC\u200D♀️", + [":woman_bowing_medium_skin_tone:"] = "\uD83D\uDE47\uD83C\uDFFD\u200D♀️", + [":woman_bowing_tone1:"] = "\uD83D\uDE47\uD83C\uDFFB\u200D♀️", + [":woman_bowing_tone2:"] = "\uD83D\uDE47\uD83C\uDFFC\u200D♀️", + [":woman_bowing_tone3:"] = "\uD83D\uDE47\uD83C\uDFFD\u200D♀️", + [":woman_bowing_tone4:"] = "\uD83D\uDE47\uD83C\uDFFE\u200D♀️", + [":woman_bowing_tone5:"] = "\uD83D\uDE47\uD83C\uDFFF\u200D♀️", + [":woman_cartwheeling:"] = "\uD83E\uDD38\u200D♀️", + [":woman_cartwheeling::skin-tone-1:"] = "\uD83E\uDD38\uD83C\uDFFB\u200D♀️", + [":woman_cartwheeling::skin-tone-2:"] = "\uD83E\uDD38\uD83C\uDFFC\u200D♀️", + [":woman_cartwheeling::skin-tone-3:"] = "\uD83E\uDD38\uD83C\uDFFD\u200D♀️", + [":woman_cartwheeling::skin-tone-4:"] = "\uD83E\uDD38\uD83C\uDFFE\u200D♀️", + [":woman_cartwheeling::skin-tone-5:"] = "\uD83E\uDD38\uD83C\uDFFF\u200D♀️", + [":woman_cartwheeling_dark_skin_tone:"] = "\uD83E\uDD38\uD83C\uDFFF\u200D♀️", + [":woman_cartwheeling_light_skin_tone:"] = "\uD83E\uDD38\uD83C\uDFFB\u200D♀️", + [":woman_cartwheeling_medium_dark_skin_tone:"] = "\uD83E\uDD38\uD83C\uDFFE\u200D♀️", + [":woman_cartwheeling_medium_light_skin_tone:"] = "\uD83E\uDD38\uD83C\uDFFC\u200D♀️", + [":woman_cartwheeling_medium_skin_tone:"] = "\uD83E\uDD38\uD83C\uDFFD\u200D♀️", + [":woman_cartwheeling_tone1:"] = "\uD83E\uDD38\uD83C\uDFFB\u200D♀️", + [":woman_cartwheeling_tone2:"] = "\uD83E\uDD38\uD83C\uDFFC\u200D♀️", + [":woman_cartwheeling_tone3:"] = "\uD83E\uDD38\uD83C\uDFFD\u200D♀️", + [":woman_cartwheeling_tone4:"] = "\uD83E\uDD38\uD83C\uDFFE\u200D♀️", + [":woman_cartwheeling_tone5:"] = "\uD83E\uDD38\uD83C\uDFFF\u200D♀️", + [":woman_climbing:"] = "\uD83E\uDDD7\u200D♀️", + [":woman_climbing::skin-tone-1:"] = "\uD83E\uDDD7\uD83C\uDFFB\u200D♀️", + [":woman_climbing::skin-tone-2:"] = "\uD83E\uDDD7\uD83C\uDFFC\u200D♀️", + [":woman_climbing::skin-tone-3:"] = "\uD83E\uDDD7\uD83C\uDFFD\u200D♀️", + [":woman_climbing::skin-tone-4:"] = "\uD83E\uDDD7\uD83C\uDFFE\u200D♀️", + [":woman_climbing::skin-tone-5:"] = "\uD83E\uDDD7\uD83C\uDFFF\u200D♀️", + [":woman_climbing_dark_skin_tone:"] = "\uD83E\uDDD7\uD83C\uDFFF\u200D♀️", + [":woman_climbing_light_skin_tone:"] = "\uD83E\uDDD7\uD83C\uDFFB\u200D♀️", + [":woman_climbing_medium_dark_skin_tone:"] = "\uD83E\uDDD7\uD83C\uDFFE\u200D♀️", + [":woman_climbing_medium_light_skin_tone:"] = "\uD83E\uDDD7\uD83C\uDFFC\u200D♀️", + [":woman_climbing_medium_skin_tone:"] = "\uD83E\uDDD7\uD83C\uDFFD\u200D♀️", + [":woman_climbing_tone1:"] = "\uD83E\uDDD7\uD83C\uDFFB\u200D♀️", + [":woman_climbing_tone2:"] = "\uD83E\uDDD7\uD83C\uDFFC\u200D♀️", + [":woman_climbing_tone3:"] = "\uD83E\uDDD7\uD83C\uDFFD\u200D♀️", + [":woman_climbing_tone4:"] = "\uD83E\uDDD7\uD83C\uDFFE\u200D♀️", + [":woman_climbing_tone5:"] = "\uD83E\uDDD7\uD83C\uDFFF\u200D♀️", + [":woman_construction_worker:"] = "\uD83D\uDC77\u200D♀️", + [":woman_construction_worker::skin-tone-1:"] = "\uD83D\uDC77\uD83C\uDFFB\u200D♀️", + [":woman_construction_worker::skin-tone-2:"] = "\uD83D\uDC77\uD83C\uDFFC\u200D♀️", + [":woman_construction_worker::skin-tone-3:"] = "\uD83D\uDC77\uD83C\uDFFD\u200D♀️", + [":woman_construction_worker::skin-tone-4:"] = "\uD83D\uDC77\uD83C\uDFFE\u200D♀️", + [":woman_construction_worker::skin-tone-5:"] = "\uD83D\uDC77\uD83C\uDFFF\u200D♀️", + [":woman_construction_worker_dark_skin_tone:"] = "\uD83D\uDC77\uD83C\uDFFF\u200D♀️", + [":woman_construction_worker_light_skin_tone:"] = "\uD83D\uDC77\uD83C\uDFFB\u200D♀️", + [":woman_construction_worker_medium_dark_skin_tone:"] = "\uD83D\uDC77\uD83C\uDFFE\u200D♀️", + [":woman_construction_worker_medium_light_skin_tone:"] = "\uD83D\uDC77\uD83C\uDFFC\u200D♀️", + [":woman_construction_worker_medium_skin_tone:"] = "\uD83D\uDC77\uD83C\uDFFD\u200D♀️", + [":woman_construction_worker_tone1:"] = "\uD83D\uDC77\uD83C\uDFFB\u200D♀️", + [":woman_construction_worker_tone2:"] = "\uD83D\uDC77\uD83C\uDFFC\u200D♀️", + [":woman_construction_worker_tone3:"] = "\uD83D\uDC77\uD83C\uDFFD\u200D♀️", + [":woman_construction_worker_tone4:"] = "\uD83D\uDC77\uD83C\uDFFE\u200D♀️", + [":woman_construction_worker_tone5:"] = "\uD83D\uDC77\uD83C\uDFFF\u200D♀️", + [":woman_cook:"] = "\uD83D\uDC69\u200D\uD83C\uDF73", + [":woman_cook::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDF73", + [":woman_cook::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDF73", + [":woman_cook::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDF73", + [":woman_cook::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDF73", + [":woman_cook::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDF73", + [":woman_cook_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDF73", + [":woman_cook_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDF73", + [":woman_cook_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDF73", + [":woman_cook_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDF73", + [":woman_cook_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDF73", + [":woman_cook_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDF73", + [":woman_cook_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDF73", + [":woman_cook_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDF73", + [":woman_cook_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDF73", + [":woman_cook_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDF73", + [":woman_curly_haired:"] = "\uD83D\uDC69\u200D\uD83E\uDDB1", + [":woman_curly_haired::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDB1", + [":woman_curly_haired::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDB1", + [":woman_curly_haired::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDB1", + [":woman_curly_haired::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDB1", + [":woman_curly_haired::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDB1", + [":woman_curly_haired_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDB1", + [":woman_curly_haired_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDB1", + [":woman_curly_haired_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDB1", + [":woman_curly_haired_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDB1", + [":woman_curly_haired_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDB1", + [":woman_curly_haired_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDB1", + [":woman_curly_haired_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDB1", + [":woman_curly_haired_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDB1", + [":woman_curly_haired_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDB1", + [":woman_curly_haired_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDB1", + [":woman_detective:"] = "\uD83D\uDD75️\u200D♀️", + [":woman_detective::skin-tone-1:"] = "\uD83D\uDD75\uD83C\uDFFB\u200D♀️", + [":woman_detective::skin-tone-2:"] = "\uD83D\uDD75\uD83C\uDFFC\u200D♀️", + [":woman_detective::skin-tone-3:"] = "\uD83D\uDD75\uD83C\uDFFD\u200D♀️", + [":woman_detective::skin-tone-4:"] = "\uD83D\uDD75\uD83C\uDFFE\u200D♀️", + [":woman_detective::skin-tone-5:"] = "\uD83D\uDD75\uD83C\uDFFF\u200D♀️", + [":woman_detective_dark_skin_tone:"] = "\uD83D\uDD75\uD83C\uDFFF\u200D♀️", + [":woman_detective_light_skin_tone:"] = "\uD83D\uDD75\uD83C\uDFFB\u200D♀️", + [":woman_detective_medium_dark_skin_tone:"] = "\uD83D\uDD75\uD83C\uDFFE\u200D♀️", + [":woman_detective_medium_light_skin_tone:"] = "\uD83D\uDD75\uD83C\uDFFC\u200D♀️", + [":woman_detective_medium_skin_tone:"] = "\uD83D\uDD75\uD83C\uDFFD\u200D♀️", + [":woman_detective_tone1:"] = "\uD83D\uDD75\uD83C\uDFFB\u200D♀️", + [":woman_detective_tone2:"] = "\uD83D\uDD75\uD83C\uDFFC\u200D♀️", + [":woman_detective_tone3:"] = "\uD83D\uDD75\uD83C\uDFFD\u200D♀️", + [":woman_detective_tone4:"] = "\uD83D\uDD75\uD83C\uDFFE\u200D♀️", + [":woman_detective_tone5:"] = "\uD83D\uDD75\uD83C\uDFFF\u200D♀️", + [":woman_elf:"] = "\uD83E\uDDDD\u200D♀️", + [":woman_elf::skin-tone-1:"] = "\uD83E\uDDDD\uD83C\uDFFB\u200D♀️", + [":woman_elf::skin-tone-2:"] = "\uD83E\uDDDD\uD83C\uDFFC\u200D♀️", + [":woman_elf::skin-tone-3:"] = "\uD83E\uDDDD\uD83C\uDFFD\u200D♀️", + [":woman_elf::skin-tone-4:"] = "\uD83E\uDDDD\uD83C\uDFFE\u200D♀️", + [":woman_elf::skin-tone-5:"] = "\uD83E\uDDDD\uD83C\uDFFF\u200D♀️", + [":woman_elf_dark_skin_tone:"] = "\uD83E\uDDDD\uD83C\uDFFF\u200D♀️", + [":woman_elf_light_skin_tone:"] = "\uD83E\uDDDD\uD83C\uDFFB\u200D♀️", + [":woman_elf_medium_dark_skin_tone:"] = "\uD83E\uDDDD\uD83C\uDFFE\u200D♀️", + [":woman_elf_medium_light_skin_tone:"] = "\uD83E\uDDDD\uD83C\uDFFC\u200D♀️", + [":woman_elf_medium_skin_tone:"] = "\uD83E\uDDDD\uD83C\uDFFD\u200D♀️", + [":woman_elf_tone1:"] = "\uD83E\uDDDD\uD83C\uDFFB\u200D♀️", + [":woman_elf_tone2:"] = "\uD83E\uDDDD\uD83C\uDFFC\u200D♀️", + [":woman_elf_tone3:"] = "\uD83E\uDDDD\uD83C\uDFFD\u200D♀️", + [":woman_elf_tone4:"] = "\uD83E\uDDDD\uD83C\uDFFE\u200D♀️", + [":woman_elf_tone5:"] = "\uD83E\uDDDD\uD83C\uDFFF\u200D♀️", + [":woman_facepalming:"] = "\uD83E\uDD26\u200D♀️", + [":woman_facepalming::skin-tone-1:"] = "\uD83E\uDD26\uD83C\uDFFB\u200D♀️", + [":woman_facepalming::skin-tone-2:"] = "\uD83E\uDD26\uD83C\uDFFC\u200D♀️", + [":woman_facepalming::skin-tone-3:"] = "\uD83E\uDD26\uD83C\uDFFD\u200D♀️", + [":woman_facepalming::skin-tone-4:"] = "\uD83E\uDD26\uD83C\uDFFE\u200D♀️", + [":woman_facepalming::skin-tone-5:"] = "\uD83E\uDD26\uD83C\uDFFF\u200D♀️", + [":woman_facepalming_dark_skin_tone:"] = "\uD83E\uDD26\uD83C\uDFFF\u200D♀️", + [":woman_facepalming_light_skin_tone:"] = "\uD83E\uDD26\uD83C\uDFFB\u200D♀️", + [":woman_facepalming_medium_dark_skin_tone:"] = "\uD83E\uDD26\uD83C\uDFFE\u200D♀️", + [":woman_facepalming_medium_light_skin_tone:"] = "\uD83E\uDD26\uD83C\uDFFC\u200D♀️", + [":woman_facepalming_medium_skin_tone:"] = "\uD83E\uDD26\uD83C\uDFFD\u200D♀️", + [":woman_facepalming_tone1:"] = "\uD83E\uDD26\uD83C\uDFFB\u200D♀️", + [":woman_facepalming_tone2:"] = "\uD83E\uDD26\uD83C\uDFFC\u200D♀️", + [":woman_facepalming_tone3:"] = "\uD83E\uDD26\uD83C\uDFFD\u200D♀️", + [":woman_facepalming_tone4:"] = "\uD83E\uDD26\uD83C\uDFFE\u200D♀️", + [":woman_facepalming_tone5:"] = "\uD83E\uDD26\uD83C\uDFFF\u200D♀️", + [":woman_factory_worker:"] = "\uD83D\uDC69\u200D\uD83C\uDFED", + [":woman_factory_worker::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDFED", + [":woman_factory_worker::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDFED", + [":woman_factory_worker::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDFED", + [":woman_factory_worker::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDFED", + [":woman_factory_worker::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDFED", + [":woman_factory_worker_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDFED", + [":woman_factory_worker_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDFED", + [":woman_factory_worker_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDFED", + [":woman_factory_worker_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDFED", + [":woman_factory_worker_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDFED", + [":woman_factory_worker_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDFED", + [":woman_factory_worker_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDFED", + [":woman_factory_worker_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDFED", + [":woman_factory_worker_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDFED", + [":woman_factory_worker_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDFED", + [":woman_fairy:"] = "\uD83E\uDDDA\u200D♀️", + [":woman_fairy::skin-tone-1:"] = "\uD83E\uDDDA\uD83C\uDFFB\u200D♀️", + [":woman_fairy::skin-tone-2:"] = "\uD83E\uDDDA\uD83C\uDFFC\u200D♀️", + [":woman_fairy::skin-tone-3:"] = "\uD83E\uDDDA\uD83C\uDFFD\u200D♀️", + [":woman_fairy::skin-tone-4:"] = "\uD83E\uDDDA\uD83C\uDFFE\u200D♀️", + [":woman_fairy::skin-tone-5:"] = "\uD83E\uDDDA\uD83C\uDFFF\u200D♀️", + [":woman_fairy_dark_skin_tone:"] = "\uD83E\uDDDA\uD83C\uDFFF\u200D♀️", + [":woman_fairy_light_skin_tone:"] = "\uD83E\uDDDA\uD83C\uDFFB\u200D♀️", + [":woman_fairy_medium_dark_skin_tone:"] = "\uD83E\uDDDA\uD83C\uDFFE\u200D♀️", + [":woman_fairy_medium_light_skin_tone:"] = "\uD83E\uDDDA\uD83C\uDFFC\u200D♀️", + [":woman_fairy_medium_skin_tone:"] = "\uD83E\uDDDA\uD83C\uDFFD\u200D♀️", + [":woman_fairy_tone1:"] = "\uD83E\uDDDA\uD83C\uDFFB\u200D♀️", + [":woman_fairy_tone2:"] = "\uD83E\uDDDA\uD83C\uDFFC\u200D♀️", + [":woman_fairy_tone3:"] = "\uD83E\uDDDA\uD83C\uDFFD\u200D♀️", + [":woman_fairy_tone4:"] = "\uD83E\uDDDA\uD83C\uDFFE\u200D♀️", + [":woman_fairy_tone5:"] = "\uD83E\uDDDA\uD83C\uDFFF\u200D♀️", + [":woman_farmer:"] = "\uD83D\uDC69\u200D\uD83C\uDF3E", + [":woman_farmer::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDF3E", + [":woman_farmer::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDF3E", + [":woman_farmer::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDF3E", + [":woman_farmer::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDF3E", + [":woman_farmer::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDF3E", + [":woman_farmer_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDF3E", + [":woman_farmer_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDF3E", + [":woman_farmer_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDF3E", + [":woman_farmer_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDF3E", + [":woman_farmer_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDF3E", + [":woman_farmer_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDF3E", + [":woman_farmer_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDF3E", + [":woman_farmer_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDF3E", + [":woman_farmer_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDF3E", + [":woman_farmer_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDF3E", + [":woman_firefighter:"] = "\uD83D\uDC69\u200D\uD83D\uDE92", + [":woman_firefighter::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDE92", + [":woman_firefighter::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDE92", + [":woman_firefighter::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDE92", + [":woman_firefighter::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDE92", + [":woman_firefighter::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDE92", + [":woman_firefighter_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDE92", + [":woman_firefighter_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDE92", + [":woman_firefighter_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDE92", + [":woman_firefighter_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDE92", + [":woman_firefighter_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDE92", + [":woman_firefighter_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDE92", + [":woman_firefighter_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDE92", + [":woman_firefighter_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDE92", + [":woman_firefighter_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDE92", + [":woman_firefighter_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDE92", + [":woman_frowning:"] = "\uD83D\uDE4D\u200D♀️", + [":woman_frowning::skin-tone-1:"] = "\uD83D\uDE4D\uD83C\uDFFB\u200D♀️", + [":woman_frowning::skin-tone-2:"] = "\uD83D\uDE4D\uD83C\uDFFC\u200D♀️", + [":woman_frowning::skin-tone-3:"] = "\uD83D\uDE4D\uD83C\uDFFD\u200D♀️", + [":woman_frowning::skin-tone-4:"] = "\uD83D\uDE4D\uD83C\uDFFE\u200D♀️", + [":woman_frowning::skin-tone-5:"] = "\uD83D\uDE4D\uD83C\uDFFF\u200D♀️", + [":woman_frowning_dark_skin_tone:"] = "\uD83D\uDE4D\uD83C\uDFFF\u200D♀️", + [":woman_frowning_light_skin_tone:"] = "\uD83D\uDE4D\uD83C\uDFFB\u200D♀️", + [":woman_frowning_medium_dark_skin_tone:"] = "\uD83D\uDE4D\uD83C\uDFFE\u200D♀️", + [":woman_frowning_medium_light_skin_tone:"] = "\uD83D\uDE4D\uD83C\uDFFC\u200D♀️", + [":woman_frowning_medium_skin_tone:"] = "\uD83D\uDE4D\uD83C\uDFFD\u200D♀️", + [":woman_frowning_tone1:"] = "\uD83D\uDE4D\uD83C\uDFFB\u200D♀️", + [":woman_frowning_tone2:"] = "\uD83D\uDE4D\uD83C\uDFFC\u200D♀️", + [":woman_frowning_tone3:"] = "\uD83D\uDE4D\uD83C\uDFFD\u200D♀️", + [":woman_frowning_tone4:"] = "\uD83D\uDE4D\uD83C\uDFFE\u200D♀️", + [":woman_frowning_tone5:"] = "\uD83D\uDE4D\uD83C\uDFFF\u200D♀️", + [":woman_genie:"] = "\uD83E\uDDDE\u200D♀️", + [":woman_gesturing_no:"] = "\uD83D\uDE45\u200D♀️", + [":woman_gesturing_no::skin-tone-1:"] = "\uD83D\uDE45\uD83C\uDFFB\u200D♀️", + [":woman_gesturing_no::skin-tone-2:"] = "\uD83D\uDE45\uD83C\uDFFC\u200D♀️", + [":woman_gesturing_no::skin-tone-3:"] = "\uD83D\uDE45\uD83C\uDFFD\u200D♀️", + [":woman_gesturing_no::skin-tone-4:"] = "\uD83D\uDE45\uD83C\uDFFE\u200D♀️", + [":woman_gesturing_no::skin-tone-5:"] = "\uD83D\uDE45\uD83C\uDFFF\u200D♀️", + [":woman_gesturing_no_dark_skin_tone:"] = "\uD83D\uDE45\uD83C\uDFFF\u200D♀️", + [":woman_gesturing_no_light_skin_tone:"] = "\uD83D\uDE45\uD83C\uDFFB\u200D♀️", + [":woman_gesturing_no_medium_dark_skin_tone:"] = "\uD83D\uDE45\uD83C\uDFFE\u200D♀️", + [":woman_gesturing_no_medium_light_skin_tone:"] = "\uD83D\uDE45\uD83C\uDFFC\u200D♀️", + [":woman_gesturing_no_medium_skin_tone:"] = "\uD83D\uDE45\uD83C\uDFFD\u200D♀️", + [":woman_gesturing_no_tone1:"] = "\uD83D\uDE45\uD83C\uDFFB\u200D♀️", + [":woman_gesturing_no_tone2:"] = "\uD83D\uDE45\uD83C\uDFFC\u200D♀️", + [":woman_gesturing_no_tone3:"] = "\uD83D\uDE45\uD83C\uDFFD\u200D♀️", + [":woman_gesturing_no_tone4:"] = "\uD83D\uDE45\uD83C\uDFFE\u200D♀️", + [":woman_gesturing_no_tone5:"] = "\uD83D\uDE45\uD83C\uDFFF\u200D♀️", + [":woman_gesturing_ok:"] = "\uD83D\uDE46\u200D♀️", + [":woman_gesturing_ok::skin-tone-1:"] = "\uD83D\uDE46\uD83C\uDFFB\u200D♀️", + [":woman_gesturing_ok::skin-tone-2:"] = "\uD83D\uDE46\uD83C\uDFFC\u200D♀️", + [":woman_gesturing_ok::skin-tone-3:"] = "\uD83D\uDE46\uD83C\uDFFD\u200D♀️", + [":woman_gesturing_ok::skin-tone-4:"] = "\uD83D\uDE46\uD83C\uDFFE\u200D♀️", + [":woman_gesturing_ok::skin-tone-5:"] = "\uD83D\uDE46\uD83C\uDFFF\u200D♀️", + [":woman_gesturing_ok_dark_skin_tone:"] = "\uD83D\uDE46\uD83C\uDFFF\u200D♀️", + [":woman_gesturing_ok_light_skin_tone:"] = "\uD83D\uDE46\uD83C\uDFFB\u200D♀️", + [":woman_gesturing_ok_medium_dark_skin_tone:"] = "\uD83D\uDE46\uD83C\uDFFE\u200D♀️", + [":woman_gesturing_ok_medium_light_skin_tone:"] = "\uD83D\uDE46\uD83C\uDFFC\u200D♀️", + [":woman_gesturing_ok_medium_skin_tone:"] = "\uD83D\uDE46\uD83C\uDFFD\u200D♀️", + [":woman_gesturing_ok_tone1:"] = "\uD83D\uDE46\uD83C\uDFFB\u200D♀️", + [":woman_gesturing_ok_tone2:"] = "\uD83D\uDE46\uD83C\uDFFC\u200D♀️", + [":woman_gesturing_ok_tone3:"] = "\uD83D\uDE46\uD83C\uDFFD\u200D♀️", + [":woman_gesturing_ok_tone4:"] = "\uD83D\uDE46\uD83C\uDFFE\u200D♀️", + [":woman_gesturing_ok_tone5:"] = "\uD83D\uDE46\uD83C\uDFFF\u200D♀️", + [":woman_getting_face_massage:"] = "\uD83D\uDC86\u200D♀️", + [":woman_getting_face_massage::skin-tone-1:"] = "\uD83D\uDC86\uD83C\uDFFB\u200D♀️", + [":woman_getting_face_massage::skin-tone-2:"] = "\uD83D\uDC86\uD83C\uDFFC\u200D♀️", + [":woman_getting_face_massage::skin-tone-3:"] = "\uD83D\uDC86\uD83C\uDFFD\u200D♀️", + [":woman_getting_face_massage::skin-tone-4:"] = "\uD83D\uDC86\uD83C\uDFFE\u200D♀️", + [":woman_getting_face_massage::skin-tone-5:"] = "\uD83D\uDC86\uD83C\uDFFF\u200D♀️", + [":woman_getting_face_massage_dark_skin_tone:"] = "\uD83D\uDC86\uD83C\uDFFF\u200D♀️", + [":woman_getting_face_massage_light_skin_tone:"] = "\uD83D\uDC86\uD83C\uDFFB\u200D♀️", + [":woman_getting_face_massage_medium_dark_skin_tone:"] = "\uD83D\uDC86\uD83C\uDFFE\u200D♀️", + [":woman_getting_face_massage_medium_light_skin_tone:"] = "\uD83D\uDC86\uD83C\uDFFC\u200D♀️", + [":woman_getting_face_massage_medium_skin_tone:"] = "\uD83D\uDC86\uD83C\uDFFD\u200D♀️", + [":woman_getting_face_massage_tone1:"] = "\uD83D\uDC86\uD83C\uDFFB\u200D♀️", + [":woman_getting_face_massage_tone2:"] = "\uD83D\uDC86\uD83C\uDFFC\u200D♀️", + [":woman_getting_face_massage_tone3:"] = "\uD83D\uDC86\uD83C\uDFFD\u200D♀️", + [":woman_getting_face_massage_tone4:"] = "\uD83D\uDC86\uD83C\uDFFE\u200D♀️", + [":woman_getting_face_massage_tone5:"] = "\uD83D\uDC86\uD83C\uDFFF\u200D♀️", + [":woman_getting_haircut:"] = "\uD83D\uDC87\u200D♀️", + [":woman_getting_haircut::skin-tone-1:"] = "\uD83D\uDC87\uD83C\uDFFB\u200D♀️", + [":woman_getting_haircut::skin-tone-2:"] = "\uD83D\uDC87\uD83C\uDFFC\u200D♀️", + [":woman_getting_haircut::skin-tone-3:"] = "\uD83D\uDC87\uD83C\uDFFD\u200D♀️", + [":woman_getting_haircut::skin-tone-4:"] = "\uD83D\uDC87\uD83C\uDFFE\u200D♀️", + [":woman_getting_haircut::skin-tone-5:"] = "\uD83D\uDC87\uD83C\uDFFF\u200D♀️", + [":woman_getting_haircut_dark_skin_tone:"] = "\uD83D\uDC87\uD83C\uDFFF\u200D♀️", + [":woman_getting_haircut_light_skin_tone:"] = "\uD83D\uDC87\uD83C\uDFFB\u200D♀️", + [":woman_getting_haircut_medium_dark_skin_tone:"] = "\uD83D\uDC87\uD83C\uDFFE\u200D♀️", + [":woman_getting_haircut_medium_light_skin_tone:"] = "\uD83D\uDC87\uD83C\uDFFC\u200D♀️", + [":woman_getting_haircut_medium_skin_tone:"] = "\uD83D\uDC87\uD83C\uDFFD\u200D♀️", + [":woman_getting_haircut_tone1:"] = "\uD83D\uDC87\uD83C\uDFFB\u200D♀️", + [":woman_getting_haircut_tone2:"] = "\uD83D\uDC87\uD83C\uDFFC\u200D♀️", + [":woman_getting_haircut_tone3:"] = "\uD83D\uDC87\uD83C\uDFFD\u200D♀️", + [":woman_getting_haircut_tone4:"] = "\uD83D\uDC87\uD83C\uDFFE\u200D♀️", + [":woman_getting_haircut_tone5:"] = "\uD83D\uDC87\uD83C\uDFFF\u200D♀️", + [":woman_golfing:"] = "\uD83C\uDFCC️\u200D♀️", + [":woman_golfing::skin-tone-1:"] = "\uD83C\uDFCC\uD83C\uDFFB\u200D♀️", + [":woman_golfing::skin-tone-2:"] = "\uD83C\uDFCC\uD83C\uDFFC\u200D♀️", + [":woman_golfing::skin-tone-3:"] = "\uD83C\uDFCC\uD83C\uDFFD\u200D♀️", + [":woman_golfing::skin-tone-4:"] = "\uD83C\uDFCC\uD83C\uDFFE\u200D♀️", + [":woman_golfing::skin-tone-5:"] = "\uD83C\uDFCC\uD83C\uDFFF\u200D♀️", + [":woman_golfing_dark_skin_tone:"] = "\uD83C\uDFCC\uD83C\uDFFF\u200D♀️", + [":woman_golfing_light_skin_tone:"] = "\uD83C\uDFCC\uD83C\uDFFB\u200D♀️", + [":woman_golfing_medium_dark_skin_tone:"] = "\uD83C\uDFCC\uD83C\uDFFE\u200D♀️", + [":woman_golfing_medium_light_skin_tone:"] = "\uD83C\uDFCC\uD83C\uDFFC\u200D♀️", + [":woman_golfing_medium_skin_tone:"] = "\uD83C\uDFCC\uD83C\uDFFD\u200D♀️", + [":woman_golfing_tone1:"] = "\uD83C\uDFCC\uD83C\uDFFB\u200D♀️", + [":woman_golfing_tone2:"] = "\uD83C\uDFCC\uD83C\uDFFC\u200D♀️", + [":woman_golfing_tone3:"] = "\uD83C\uDFCC\uD83C\uDFFD\u200D♀️", + [":woman_golfing_tone4:"] = "\uD83C\uDFCC\uD83C\uDFFE\u200D♀️", + [":woman_golfing_tone5:"] = "\uD83C\uDFCC\uD83C\uDFFF\u200D♀️", + [":woman_guard:"] = "\uD83D\uDC82\u200D♀️", + [":woman_guard::skin-tone-1:"] = "\uD83D\uDC82\uD83C\uDFFB\u200D♀️", + [":woman_guard::skin-tone-2:"] = "\uD83D\uDC82\uD83C\uDFFC\u200D♀️", + [":woman_guard::skin-tone-3:"] = "\uD83D\uDC82\uD83C\uDFFD\u200D♀️", + [":woman_guard::skin-tone-4:"] = "\uD83D\uDC82\uD83C\uDFFE\u200D♀️", + [":woman_guard::skin-tone-5:"] = "\uD83D\uDC82\uD83C\uDFFF\u200D♀️", + [":woman_guard_dark_skin_tone:"] = "\uD83D\uDC82\uD83C\uDFFF\u200D♀️", + [":woman_guard_light_skin_tone:"] = "\uD83D\uDC82\uD83C\uDFFB\u200D♀️", + [":woman_guard_medium_dark_skin_tone:"] = "\uD83D\uDC82\uD83C\uDFFE\u200D♀️", + [":woman_guard_medium_light_skin_tone:"] = "\uD83D\uDC82\uD83C\uDFFC\u200D♀️", + [":woman_guard_medium_skin_tone:"] = "\uD83D\uDC82\uD83C\uDFFD\u200D♀️", + [":woman_guard_tone1:"] = "\uD83D\uDC82\uD83C\uDFFB\u200D♀️", + [":woman_guard_tone2:"] = "\uD83D\uDC82\uD83C\uDFFC\u200D♀️", + [":woman_guard_tone3:"] = "\uD83D\uDC82\uD83C\uDFFD\u200D♀️", + [":woman_guard_tone4:"] = "\uD83D\uDC82\uD83C\uDFFE\u200D♀️", + [":woman_guard_tone5:"] = "\uD83D\uDC82\uD83C\uDFFF\u200D♀️", + [":woman_health_worker:"] = "\uD83D\uDC69\u200D⚕️", + [":woman_health_worker::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D⚕️", + [":woman_health_worker::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D⚕️", + [":woman_health_worker::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D⚕️", + [":woman_health_worker::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D⚕️", + [":woman_health_worker::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D⚕️", + [":woman_health_worker_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D⚕️", + [":woman_health_worker_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D⚕️", + [":woman_health_worker_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D⚕️", + [":woman_health_worker_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D⚕️", + [":woman_health_worker_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D⚕️", + [":woman_health_worker_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D⚕️", + [":woman_health_worker_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D⚕️", + [":woman_health_worker_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D⚕️", + [":woman_health_worker_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D⚕️", + [":woman_health_worker_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D⚕️", + [":woman_in_lotus_position:"] = "\uD83E\uDDD8\u200D♀️", + [":woman_in_lotus_position::skin-tone-1:"] = "\uD83E\uDDD8\uD83C\uDFFB\u200D♀️", + [":woman_in_lotus_position::skin-tone-2:"] = "\uD83E\uDDD8\uD83C\uDFFC\u200D♀️", + [":woman_in_lotus_position::skin-tone-3:"] = "\uD83E\uDDD8\uD83C\uDFFD\u200D♀️", + [":woman_in_lotus_position::skin-tone-4:"] = "\uD83E\uDDD8\uD83C\uDFFE\u200D♀️", + [":woman_in_lotus_position::skin-tone-5:"] = "\uD83E\uDDD8\uD83C\uDFFF\u200D♀️", + [":woman_in_lotus_position_dark_skin_tone:"] = "\uD83E\uDDD8\uD83C\uDFFF\u200D♀️", + [":woman_in_lotus_position_light_skin_tone:"] = "\uD83E\uDDD8\uD83C\uDFFB\u200D♀️", + [":woman_in_lotus_position_medium_dark_skin_tone:"] = "\uD83E\uDDD8\uD83C\uDFFE\u200D♀️", + [":woman_in_lotus_position_medium_light_skin_tone:"] = "\uD83E\uDDD8\uD83C\uDFFC\u200D♀️", + [":woman_in_lotus_position_medium_skin_tone:"] = "\uD83E\uDDD8\uD83C\uDFFD\u200D♀️", + [":woman_in_lotus_position_tone1:"] = "\uD83E\uDDD8\uD83C\uDFFB\u200D♀️", + [":woman_in_lotus_position_tone2:"] = "\uD83E\uDDD8\uD83C\uDFFC\u200D♀️", + [":woman_in_lotus_position_tone3:"] = "\uD83E\uDDD8\uD83C\uDFFD\u200D♀️", + [":woman_in_lotus_position_tone4:"] = "\uD83E\uDDD8\uD83C\uDFFE\u200D♀️", + [":woman_in_lotus_position_tone5:"] = "\uD83E\uDDD8\uD83C\uDFFF\u200D♀️", + [":woman_in_manual_wheelchair:"] = "\uD83D\uDC69\u200D\uD83E\uDDBD", + [":woman_in_manual_wheelchair::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDBD", + [":woman_in_manual_wheelchair::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDBD", + [":woman_in_manual_wheelchair::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDBD", + [":woman_in_manual_wheelchair::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDBD", + [":woman_in_manual_wheelchair::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDBD", + [":woman_in_manual_wheelchair_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDBD", + [":woman_in_manual_wheelchair_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDBD", + [":woman_in_manual_wheelchair_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDBD", + [":woman_in_manual_wheelchair_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDBD", + [":woman_in_manual_wheelchair_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDBD", + [":woman_in_manual_wheelchair_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDBD", + [":woman_in_manual_wheelchair_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDBD", + [":woman_in_manual_wheelchair_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDBD", + [":woman_in_manual_wheelchair_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDBD", + [":woman_in_manual_wheelchair_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDBD", + [":woman_in_motorized_wheelchair:"] = "\uD83D\uDC69\u200D\uD83E\uDDBC", + [":woman_in_motorized_wheelchair::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDBC", + [":woman_in_motorized_wheelchair::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDBC", + [":woman_in_motorized_wheelchair::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDBC", + [":woman_in_motorized_wheelchair::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDBC", + [":woman_in_motorized_wheelchair::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDBC", + [":woman_in_motorized_wheelchair_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDBC", + [":woman_in_motorized_wheelchair_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDBC", + [":woman_in_motorized_wheelchair_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDBC", + [":woman_in_motorized_wheelchair_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDBC", + [":woman_in_motorized_wheelchair_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDBC", + [":woman_in_motorized_wheelchair_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDBC", + [":woman_in_motorized_wheelchair_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDBC", + [":woman_in_motorized_wheelchair_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDBC", + [":woman_in_motorized_wheelchair_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDBC", + [":woman_in_motorized_wheelchair_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDBC", + [":woman_in_steamy_room:"] = "\uD83E\uDDD6\u200D♀️", + [":woman_in_steamy_room::skin-tone-1:"] = "\uD83E\uDDD6\uD83C\uDFFB\u200D♀️", + [":woman_in_steamy_room::skin-tone-2:"] = "\uD83E\uDDD6\uD83C\uDFFC\u200D♀️", + [":woman_in_steamy_room::skin-tone-3:"] = "\uD83E\uDDD6\uD83C\uDFFD\u200D♀️", + [":woman_in_steamy_room::skin-tone-4:"] = "\uD83E\uDDD6\uD83C\uDFFE\u200D♀️", + [":woman_in_steamy_room::skin-tone-5:"] = "\uD83E\uDDD6\uD83C\uDFFF\u200D♀️", + [":woman_in_steamy_room_dark_skin_tone:"] = "\uD83E\uDDD6\uD83C\uDFFF\u200D♀️", + [":woman_in_steamy_room_light_skin_tone:"] = "\uD83E\uDDD6\uD83C\uDFFB\u200D♀️", + [":woman_in_steamy_room_medium_dark_skin_tone:"] = "\uD83E\uDDD6\uD83C\uDFFE\u200D♀️", + [":woman_in_steamy_room_medium_light_skin_tone:"] = "\uD83E\uDDD6\uD83C\uDFFC\u200D♀️", + [":woman_in_steamy_room_medium_skin_tone:"] = "\uD83E\uDDD6\uD83C\uDFFD\u200D♀️", + [":woman_in_steamy_room_tone1:"] = "\uD83E\uDDD6\uD83C\uDFFB\u200D♀️", + [":woman_in_steamy_room_tone2:"] = "\uD83E\uDDD6\uD83C\uDFFC\u200D♀️", + [":woman_in_steamy_room_tone3:"] = "\uD83E\uDDD6\uD83C\uDFFD\u200D♀️", + [":woman_in_steamy_room_tone4:"] = "\uD83E\uDDD6\uD83C\uDFFE\u200D♀️", + [":woman_in_steamy_room_tone5:"] = "\uD83E\uDDD6\uD83C\uDFFF\u200D♀️", + [":woman_judge:"] = "\uD83D\uDC69\u200D⚖️", + [":woman_judge::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D⚖️", + [":woman_judge::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D⚖️", + [":woman_judge::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D⚖️", + [":woman_judge::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D⚖️", + [":woman_judge::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D⚖️", + [":woman_judge_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D⚖️", + [":woman_judge_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D⚖️", + [":woman_judge_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D⚖️", + [":woman_judge_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D⚖️", + [":woman_judge_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D⚖️", + [":woman_judge_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D⚖️", + [":woman_judge_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D⚖️", + [":woman_judge_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D⚖️", + [":woman_judge_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D⚖️", + [":woman_judge_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D⚖️", + [":woman_juggling:"] = "\uD83E\uDD39\u200D♀️", + [":woman_juggling::skin-tone-1:"] = "\uD83E\uDD39\uD83C\uDFFB\u200D♀️", + [":woman_juggling::skin-tone-2:"] = "\uD83E\uDD39\uD83C\uDFFC\u200D♀️", + [":woman_juggling::skin-tone-3:"] = "\uD83E\uDD39\uD83C\uDFFD\u200D♀️", + [":woman_juggling::skin-tone-4:"] = "\uD83E\uDD39\uD83C\uDFFE\u200D♀️", + [":woman_juggling::skin-tone-5:"] = "\uD83E\uDD39\uD83C\uDFFF\u200D♀️", + [":woman_juggling_dark_skin_tone:"] = "\uD83E\uDD39\uD83C\uDFFF\u200D♀️", + [":woman_juggling_light_skin_tone:"] = "\uD83E\uDD39\uD83C\uDFFB\u200D♀️", + [":woman_juggling_medium_dark_skin_tone:"] = "\uD83E\uDD39\uD83C\uDFFE\u200D♀️", + [":woman_juggling_medium_light_skin_tone:"] = "\uD83E\uDD39\uD83C\uDFFC\u200D♀️", + [":woman_juggling_medium_skin_tone:"] = "\uD83E\uDD39\uD83C\uDFFD\u200D♀️", + [":woman_juggling_tone1:"] = "\uD83E\uDD39\uD83C\uDFFB\u200D♀️", + [":woman_juggling_tone2:"] = "\uD83E\uDD39\uD83C\uDFFC\u200D♀️", + [":woman_juggling_tone3:"] = "\uD83E\uDD39\uD83C\uDFFD\u200D♀️", + [":woman_juggling_tone4:"] = "\uD83E\uDD39\uD83C\uDFFE\u200D♀️", + [":woman_juggling_tone5:"] = "\uD83E\uDD39\uD83C\uDFFF\u200D♀️", + [":woman_kneeling:"] = "\uD83E\uDDCE\u200D♀️", + [":woman_kneeling::skin-tone-1:"] = "\uD83E\uDDCE\uD83C\uDFFB\u200D♀️", + [":woman_kneeling::skin-tone-2:"] = "\uD83E\uDDCE\uD83C\uDFFC\u200D♀️", + [":woman_kneeling::skin-tone-3:"] = "\uD83E\uDDCE\uD83C\uDFFD\u200D♀️", + [":woman_kneeling::skin-tone-4:"] = "\uD83E\uDDCE\uD83C\uDFFE\u200D♀️", + [":woman_kneeling::skin-tone-5:"] = "\uD83E\uDDCE\uD83C\uDFFF\u200D♀️", + [":woman_kneeling_dark_skin_tone:"] = "\uD83E\uDDCE\uD83C\uDFFF\u200D♀️", + [":woman_kneeling_light_skin_tone:"] = "\uD83E\uDDCE\uD83C\uDFFB\u200D♀️", + [":woman_kneeling_medium_dark_skin_tone:"] = "\uD83E\uDDCE\uD83C\uDFFE\u200D♀️", + [":woman_kneeling_medium_light_skin_tone:"] = "\uD83E\uDDCE\uD83C\uDFFC\u200D♀️", + [":woman_kneeling_medium_skin_tone:"] = "\uD83E\uDDCE\uD83C\uDFFD\u200D♀️", + [":woman_kneeling_tone1:"] = "\uD83E\uDDCE\uD83C\uDFFB\u200D♀️", + [":woman_kneeling_tone2:"] = "\uD83E\uDDCE\uD83C\uDFFC\u200D♀️", + [":woman_kneeling_tone3:"] = "\uD83E\uDDCE\uD83C\uDFFD\u200D♀️", + [":woman_kneeling_tone4:"] = "\uD83E\uDDCE\uD83C\uDFFE\u200D♀️", + [":woman_kneeling_tone5:"] = "\uD83E\uDDCE\uD83C\uDFFF\u200D♀️", + [":woman_lifting_weights:"] = "\uD83C\uDFCB️\u200D♀️", + [":woman_lifting_weights::skin-tone-1:"] = "\uD83C\uDFCB\uD83C\uDFFB\u200D♀️", + [":woman_lifting_weights::skin-tone-2:"] = "\uD83C\uDFCB\uD83C\uDFFC\u200D♀️", + [":woman_lifting_weights::skin-tone-3:"] = "\uD83C\uDFCB\uD83C\uDFFD\u200D♀️", + [":woman_lifting_weights::skin-tone-4:"] = "\uD83C\uDFCB\uD83C\uDFFE\u200D♀️", + [":woman_lifting_weights::skin-tone-5:"] = "\uD83C\uDFCB\uD83C\uDFFF\u200D♀️", + [":woman_lifting_weights_dark_skin_tone:"] = "\uD83C\uDFCB\uD83C\uDFFF\u200D♀️", + [":woman_lifting_weights_light_skin_tone:"] = "\uD83C\uDFCB\uD83C\uDFFB\u200D♀️", + [":woman_lifting_weights_medium_dark_skin_tone:"] = "\uD83C\uDFCB\uD83C\uDFFE\u200D♀️", + [":woman_lifting_weights_medium_light_skin_tone:"] = "\uD83C\uDFCB\uD83C\uDFFC\u200D♀️", + [":woman_lifting_weights_medium_skin_tone:"] = "\uD83C\uDFCB\uD83C\uDFFD\u200D♀️", + [":woman_lifting_weights_tone1:"] = "\uD83C\uDFCB\uD83C\uDFFB\u200D♀️", + [":woman_lifting_weights_tone2:"] = "\uD83C\uDFCB\uD83C\uDFFC\u200D♀️", + [":woman_lifting_weights_tone3:"] = "\uD83C\uDFCB\uD83C\uDFFD\u200D♀️", + [":woman_lifting_weights_tone4:"] = "\uD83C\uDFCB\uD83C\uDFFE\u200D♀️", + [":woman_lifting_weights_tone5:"] = "\uD83C\uDFCB\uD83C\uDFFF\u200D♀️", + [":woman_mage:"] = "\uD83E\uDDD9\u200D♀️", + [":woman_mage::skin-tone-1:"] = "\uD83E\uDDD9\uD83C\uDFFB\u200D♀️", + [":woman_mage::skin-tone-2:"] = "\uD83E\uDDD9\uD83C\uDFFC\u200D♀️", + [":woman_mage::skin-tone-3:"] = "\uD83E\uDDD9\uD83C\uDFFD\u200D♀️", + [":woman_mage::skin-tone-4:"] = "\uD83E\uDDD9\uD83C\uDFFE\u200D♀️", + [":woman_mage::skin-tone-5:"] = "\uD83E\uDDD9\uD83C\uDFFF\u200D♀️", + [":woman_mage_dark_skin_tone:"] = "\uD83E\uDDD9\uD83C\uDFFF\u200D♀️", + [":woman_mage_light_skin_tone:"] = "\uD83E\uDDD9\uD83C\uDFFB\u200D♀️", + [":woman_mage_medium_dark_skin_tone:"] = "\uD83E\uDDD9\uD83C\uDFFE\u200D♀️", + [":woman_mage_medium_light_skin_tone:"] = "\uD83E\uDDD9\uD83C\uDFFC\u200D♀️", + [":woman_mage_medium_skin_tone:"] = "\uD83E\uDDD9\uD83C\uDFFD\u200D♀️", + [":woman_mage_tone1:"] = "\uD83E\uDDD9\uD83C\uDFFB\u200D♀️", + [":woman_mage_tone2:"] = "\uD83E\uDDD9\uD83C\uDFFC\u200D♀️", + [":woman_mage_tone3:"] = "\uD83E\uDDD9\uD83C\uDFFD\u200D♀️", + [":woman_mage_tone4:"] = "\uD83E\uDDD9\uD83C\uDFFE\u200D♀️", + [":woman_mage_tone5:"] = "\uD83E\uDDD9\uD83C\uDFFF\u200D♀️", + [":woman_mechanic:"] = "\uD83D\uDC69\u200D\uD83D\uDD27", + [":woman_mechanic::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDD27", + [":woman_mechanic::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDD27", + [":woman_mechanic::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDD27", + [":woman_mechanic::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDD27", + [":woman_mechanic::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDD27", + [":woman_mechanic_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDD27", + [":woman_mechanic_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDD27", + [":woman_mechanic_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDD27", + [":woman_mechanic_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDD27", + [":woman_mechanic_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDD27", + [":woman_mechanic_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDD27", + [":woman_mechanic_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDD27", + [":woman_mechanic_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDD27", + [":woman_mechanic_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDD27", + [":woman_mechanic_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDD27", + [":woman_mountain_biking:"] = "\uD83D\uDEB5\u200D♀️", + [":woman_mountain_biking::skin-tone-1:"] = "\uD83D\uDEB5\uD83C\uDFFB\u200D♀️", + [":woman_mountain_biking::skin-tone-2:"] = "\uD83D\uDEB5\uD83C\uDFFC\u200D♀️", + [":woman_mountain_biking::skin-tone-3:"] = "\uD83D\uDEB5\uD83C\uDFFD\u200D♀️", + [":woman_mountain_biking::skin-tone-4:"] = "\uD83D\uDEB5\uD83C\uDFFE\u200D♀️", + [":woman_mountain_biking::skin-tone-5:"] = "\uD83D\uDEB5\uD83C\uDFFF\u200D♀️", + [":woman_mountain_biking_dark_skin_tone:"] = "\uD83D\uDEB5\uD83C\uDFFF\u200D♀️", + [":woman_mountain_biking_light_skin_tone:"] = "\uD83D\uDEB5\uD83C\uDFFB\u200D♀️", + [":woman_mountain_biking_medium_dark_skin_tone:"] = "\uD83D\uDEB5\uD83C\uDFFE\u200D♀️", + [":woman_mountain_biking_medium_light_skin_tone:"] = "\uD83D\uDEB5\uD83C\uDFFC\u200D♀️", + [":woman_mountain_biking_medium_skin_tone:"] = "\uD83D\uDEB5\uD83C\uDFFD\u200D♀️", + [":woman_mountain_biking_tone1:"] = "\uD83D\uDEB5\uD83C\uDFFB\u200D♀️", + [":woman_mountain_biking_tone2:"] = "\uD83D\uDEB5\uD83C\uDFFC\u200D♀️", + [":woman_mountain_biking_tone3:"] = "\uD83D\uDEB5\uD83C\uDFFD\u200D♀️", + [":woman_mountain_biking_tone4:"] = "\uD83D\uDEB5\uD83C\uDFFE\u200D♀️", + [":woman_mountain_biking_tone5:"] = "\uD83D\uDEB5\uD83C\uDFFF\u200D♀️", + [":woman_office_worker:"] = "\uD83D\uDC69\u200D\uD83D\uDCBC", + [":woman_office_worker::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDCBC", + [":woman_office_worker::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDCBC", + [":woman_office_worker::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDCBC", + [":woman_office_worker::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDCBC", + [":woman_office_worker::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDCBC", + [":woman_office_worker_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDCBC", + [":woman_office_worker_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDCBC", + [":woman_office_worker_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDCBC", + [":woman_office_worker_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDCBC", + [":woman_office_worker_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDCBC", + [":woman_office_worker_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDCBC", + [":woman_office_worker_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDCBC", + [":woman_office_worker_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDCBC", + [":woman_office_worker_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDCBC", + [":woman_office_worker_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDCBC", + [":woman_pilot:"] = "\uD83D\uDC69\u200D✈️", + [":woman_pilot::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D✈️", + [":woman_pilot::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D✈️", + [":woman_pilot::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D✈️", + [":woman_pilot::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D✈️", + [":woman_pilot::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D✈️", + [":woman_pilot_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D✈️", + [":woman_pilot_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D✈️", + [":woman_pilot_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D✈️", + [":woman_pilot_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D✈️", + [":woman_pilot_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D✈️", + [":woman_pilot_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D✈️", + [":woman_pilot_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D✈️", + [":woman_pilot_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D✈️", + [":woman_pilot_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D✈️", + [":woman_pilot_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D✈️", + [":woman_playing_handball:"] = "\uD83E\uDD3E\u200D♀️", + [":woman_playing_handball::skin-tone-1:"] = "\uD83E\uDD3E\uD83C\uDFFB\u200D♀️", + [":woman_playing_handball::skin-tone-2:"] = "\uD83E\uDD3E\uD83C\uDFFC\u200D♀️", + [":woman_playing_handball::skin-tone-3:"] = "\uD83E\uDD3E\uD83C\uDFFD\u200D♀️", + [":woman_playing_handball::skin-tone-4:"] = "\uD83E\uDD3E\uD83C\uDFFE\u200D♀️", + [":woman_playing_handball::skin-tone-5:"] = "\uD83E\uDD3E\uD83C\uDFFF\u200D♀️", + [":woman_playing_handball_dark_skin_tone:"] = "\uD83E\uDD3E\uD83C\uDFFF\u200D♀️", + [":woman_playing_handball_light_skin_tone:"] = "\uD83E\uDD3E\uD83C\uDFFB\u200D♀️", + [":woman_playing_handball_medium_dark_skin_tone:"] = "\uD83E\uDD3E\uD83C\uDFFE\u200D♀️", + [":woman_playing_handball_medium_light_skin_tone:"] = "\uD83E\uDD3E\uD83C\uDFFC\u200D♀️", + [":woman_playing_handball_medium_skin_tone:"] = "\uD83E\uDD3E\uD83C\uDFFD\u200D♀️", + [":woman_playing_handball_tone1:"] = "\uD83E\uDD3E\uD83C\uDFFB\u200D♀️", + [":woman_playing_handball_tone2:"] = "\uD83E\uDD3E\uD83C\uDFFC\u200D♀️", + [":woman_playing_handball_tone3:"] = "\uD83E\uDD3E\uD83C\uDFFD\u200D♀️", + [":woman_playing_handball_tone4:"] = "\uD83E\uDD3E\uD83C\uDFFE\u200D♀️", + [":woman_playing_handball_tone5:"] = "\uD83E\uDD3E\uD83C\uDFFF\u200D♀️", + [":woman_playing_water_polo:"] = "\uD83E\uDD3D\u200D♀️", + [":woman_playing_water_polo::skin-tone-1:"] = "\uD83E\uDD3D\uD83C\uDFFB\u200D♀️", + [":woman_playing_water_polo::skin-tone-2:"] = "\uD83E\uDD3D\uD83C\uDFFC\u200D♀️", + [":woman_playing_water_polo::skin-tone-3:"] = "\uD83E\uDD3D\uD83C\uDFFD\u200D♀️", + [":woman_playing_water_polo::skin-tone-4:"] = "\uD83E\uDD3D\uD83C\uDFFE\u200D♀️", + [":woman_playing_water_polo::skin-tone-5:"] = "\uD83E\uDD3D\uD83C\uDFFF\u200D♀️", + [":woman_playing_water_polo_dark_skin_tone:"] = "\uD83E\uDD3D\uD83C\uDFFF\u200D♀️", + [":woman_playing_water_polo_light_skin_tone:"] = "\uD83E\uDD3D\uD83C\uDFFB\u200D♀️", + [":woman_playing_water_polo_medium_dark_skin_tone:"] = "\uD83E\uDD3D\uD83C\uDFFE\u200D♀️", + [":woman_playing_water_polo_medium_light_skin_tone:"] = "\uD83E\uDD3D\uD83C\uDFFC\u200D♀️", + [":woman_playing_water_polo_medium_skin_tone:"] = "\uD83E\uDD3D\uD83C\uDFFD\u200D♀️", + [":woman_playing_water_polo_tone1:"] = "\uD83E\uDD3D\uD83C\uDFFB\u200D♀️", + [":woman_playing_water_polo_tone2:"] = "\uD83E\uDD3D\uD83C\uDFFC\u200D♀️", + [":woman_playing_water_polo_tone3:"] = "\uD83E\uDD3D\uD83C\uDFFD\u200D♀️", + [":woman_playing_water_polo_tone4:"] = "\uD83E\uDD3D\uD83C\uDFFE\u200D♀️", + [":woman_playing_water_polo_tone5:"] = "\uD83E\uDD3D\uD83C\uDFFF\u200D♀️", + [":woman_police_officer:"] = "\uD83D\uDC6E\u200D♀️", + [":woman_police_officer::skin-tone-1:"] = "\uD83D\uDC6E\uD83C\uDFFB\u200D♀️", + [":woman_police_officer::skin-tone-2:"] = "\uD83D\uDC6E\uD83C\uDFFC\u200D♀️", + [":woman_police_officer::skin-tone-3:"] = "\uD83D\uDC6E\uD83C\uDFFD\u200D♀️", + [":woman_police_officer::skin-tone-4:"] = "\uD83D\uDC6E\uD83C\uDFFE\u200D♀️", + [":woman_police_officer::skin-tone-5:"] = "\uD83D\uDC6E\uD83C\uDFFF\u200D♀️", + [":woman_police_officer_dark_skin_tone:"] = "\uD83D\uDC6E\uD83C\uDFFF\u200D♀️", + [":woman_police_officer_light_skin_tone:"] = "\uD83D\uDC6E\uD83C\uDFFB\u200D♀️", + [":woman_police_officer_medium_dark_skin_tone:"] = "\uD83D\uDC6E\uD83C\uDFFE\u200D♀️", + [":woman_police_officer_medium_light_skin_tone:"] = "\uD83D\uDC6E\uD83C\uDFFC\u200D♀️", + [":woman_police_officer_medium_skin_tone:"] = "\uD83D\uDC6E\uD83C\uDFFD\u200D♀️", + [":woman_police_officer_tone1:"] = "\uD83D\uDC6E\uD83C\uDFFB\u200D♀️", + [":woman_police_officer_tone2:"] = "\uD83D\uDC6E\uD83C\uDFFC\u200D♀️", + [":woman_police_officer_tone3:"] = "\uD83D\uDC6E\uD83C\uDFFD\u200D♀️", + [":woman_police_officer_tone4:"] = "\uD83D\uDC6E\uD83C\uDFFE\u200D♀️", + [":woman_police_officer_tone5:"] = "\uD83D\uDC6E\uD83C\uDFFF\u200D♀️", + [":woman_pouting:"] = "\uD83D\uDE4E\u200D♀️", + [":woman_pouting::skin-tone-1:"] = "\uD83D\uDE4E\uD83C\uDFFB\u200D♀️", + [":woman_pouting::skin-tone-2:"] = "\uD83D\uDE4E\uD83C\uDFFC\u200D♀️", + [":woman_pouting::skin-tone-3:"] = "\uD83D\uDE4E\uD83C\uDFFD\u200D♀️", + [":woman_pouting::skin-tone-4:"] = "\uD83D\uDE4E\uD83C\uDFFE\u200D♀️", + [":woman_pouting::skin-tone-5:"] = "\uD83D\uDE4E\uD83C\uDFFF\u200D♀️", + [":woman_pouting_dark_skin_tone:"] = "\uD83D\uDE4E\uD83C\uDFFF\u200D♀️", + [":woman_pouting_light_skin_tone:"] = "\uD83D\uDE4E\uD83C\uDFFB\u200D♀️", + [":woman_pouting_medium_dark_skin_tone:"] = "\uD83D\uDE4E\uD83C\uDFFE\u200D♀️", + [":woman_pouting_medium_light_skin_tone:"] = "\uD83D\uDE4E\uD83C\uDFFC\u200D♀️", + [":woman_pouting_medium_skin_tone:"] = "\uD83D\uDE4E\uD83C\uDFFD\u200D♀️", + [":woman_pouting_tone1:"] = "\uD83D\uDE4E\uD83C\uDFFB\u200D♀️", + [":woman_pouting_tone2:"] = "\uD83D\uDE4E\uD83C\uDFFC\u200D♀️", + [":woman_pouting_tone3:"] = "\uD83D\uDE4E\uD83C\uDFFD\u200D♀️", + [":woman_pouting_tone4:"] = "\uD83D\uDE4E\uD83C\uDFFE\u200D♀️", + [":woman_pouting_tone5:"] = "\uD83D\uDE4E\uD83C\uDFFF\u200D♀️", + [":woman_raising_hand:"] = "\uD83D\uDE4B\u200D♀️", + [":woman_raising_hand::skin-tone-1:"] = "\uD83D\uDE4B\uD83C\uDFFB\u200D♀️", + [":woman_raising_hand::skin-tone-2:"] = "\uD83D\uDE4B\uD83C\uDFFC\u200D♀️", + [":woman_raising_hand::skin-tone-3:"] = "\uD83D\uDE4B\uD83C\uDFFD\u200D♀️", + [":woman_raising_hand::skin-tone-4:"] = "\uD83D\uDE4B\uD83C\uDFFE\u200D♀️", + [":woman_raising_hand::skin-tone-5:"] = "\uD83D\uDE4B\uD83C\uDFFF\u200D♀️", + [":woman_raising_hand_dark_skin_tone:"] = "\uD83D\uDE4B\uD83C\uDFFF\u200D♀️", + [":woman_raising_hand_light_skin_tone:"] = "\uD83D\uDE4B\uD83C\uDFFB\u200D♀️", + [":woman_raising_hand_medium_dark_skin_tone:"] = "\uD83D\uDE4B\uD83C\uDFFE\u200D♀️", + [":woman_raising_hand_medium_light_skin_tone:"] = "\uD83D\uDE4B\uD83C\uDFFC\u200D♀️", + [":woman_raising_hand_medium_skin_tone:"] = "\uD83D\uDE4B\uD83C\uDFFD\u200D♀️", + [":woman_raising_hand_tone1:"] = "\uD83D\uDE4B\uD83C\uDFFB\u200D♀️", + [":woman_raising_hand_tone2:"] = "\uD83D\uDE4B\uD83C\uDFFC\u200D♀️", + [":woman_raising_hand_tone3:"] = "\uD83D\uDE4B\uD83C\uDFFD\u200D♀️", + [":woman_raising_hand_tone4:"] = "\uD83D\uDE4B\uD83C\uDFFE\u200D♀️", + [":woman_raising_hand_tone5:"] = "\uD83D\uDE4B\uD83C\uDFFF\u200D♀️", + [":woman_red_haired:"] = "\uD83D\uDC69\u200D\uD83E\uDDB0", + [":woman_red_haired::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDB0", + [":woman_red_haired::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDB0", + [":woman_red_haired::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDB0", + [":woman_red_haired::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDB0", + [":woman_red_haired::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDB0", + [":woman_red_haired_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDB0", + [":woman_red_haired_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDB0", + [":woman_red_haired_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDB0", + [":woman_red_haired_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDB0", + [":woman_red_haired_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDB0", + [":woman_red_haired_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDB0", + [":woman_red_haired_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDB0", + [":woman_red_haired_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDB0", + [":woman_red_haired_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDB0", + [":woman_red_haired_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDB0", + [":woman_rowing_boat:"] = "\uD83D\uDEA3\u200D♀️", + [":woman_rowing_boat::skin-tone-1:"] = "\uD83D\uDEA3\uD83C\uDFFB\u200D♀️", + [":woman_rowing_boat::skin-tone-2:"] = "\uD83D\uDEA3\uD83C\uDFFC\u200D♀️", + [":woman_rowing_boat::skin-tone-3:"] = "\uD83D\uDEA3\uD83C\uDFFD\u200D♀️", + [":woman_rowing_boat::skin-tone-4:"] = "\uD83D\uDEA3\uD83C\uDFFE\u200D♀️", + [":woman_rowing_boat::skin-tone-5:"] = "\uD83D\uDEA3\uD83C\uDFFF\u200D♀️", + [":woman_rowing_boat_dark_skin_tone:"] = "\uD83D\uDEA3\uD83C\uDFFF\u200D♀️", + [":woman_rowing_boat_light_skin_tone:"] = "\uD83D\uDEA3\uD83C\uDFFB\u200D♀️", + [":woman_rowing_boat_medium_dark_skin_tone:"] = "\uD83D\uDEA3\uD83C\uDFFE\u200D♀️", + [":woman_rowing_boat_medium_light_skin_tone:"] = "\uD83D\uDEA3\uD83C\uDFFC\u200D♀️", + [":woman_rowing_boat_medium_skin_tone:"] = "\uD83D\uDEA3\uD83C\uDFFD\u200D♀️", + [":woman_rowing_boat_tone1:"] = "\uD83D\uDEA3\uD83C\uDFFB\u200D♀️", + [":woman_rowing_boat_tone2:"] = "\uD83D\uDEA3\uD83C\uDFFC\u200D♀️", + [":woman_rowing_boat_tone3:"] = "\uD83D\uDEA3\uD83C\uDFFD\u200D♀️", + [":woman_rowing_boat_tone4:"] = "\uD83D\uDEA3\uD83C\uDFFE\u200D♀️", + [":woman_rowing_boat_tone5:"] = "\uD83D\uDEA3\uD83C\uDFFF\u200D♀️", + [":woman_running:"] = "\uD83C\uDFC3\u200D♀️", + [":woman_running::skin-tone-1:"] = "\uD83C\uDFC3\uD83C\uDFFB\u200D♀️", + [":woman_running::skin-tone-2:"] = "\uD83C\uDFC3\uD83C\uDFFC\u200D♀️", + [":woman_running::skin-tone-3:"] = "\uD83C\uDFC3\uD83C\uDFFD\u200D♀️", + [":woman_running::skin-tone-4:"] = "\uD83C\uDFC3\uD83C\uDFFE\u200D♀️", + [":woman_running::skin-tone-5:"] = "\uD83C\uDFC3\uD83C\uDFFF\u200D♀️", + [":woman_running_dark_skin_tone:"] = "\uD83C\uDFC3\uD83C\uDFFF\u200D♀️", + [":woman_running_light_skin_tone:"] = "\uD83C\uDFC3\uD83C\uDFFB\u200D♀️", + [":woman_running_medium_dark_skin_tone:"] = "\uD83C\uDFC3\uD83C\uDFFE\u200D♀️", + [":woman_running_medium_light_skin_tone:"] = "\uD83C\uDFC3\uD83C\uDFFC\u200D♀️", + [":woman_running_medium_skin_tone:"] = "\uD83C\uDFC3\uD83C\uDFFD\u200D♀️", + [":woman_running_tone1:"] = "\uD83C\uDFC3\uD83C\uDFFB\u200D♀️", + [":woman_running_tone2:"] = "\uD83C\uDFC3\uD83C\uDFFC\u200D♀️", + [":woman_running_tone3:"] = "\uD83C\uDFC3\uD83C\uDFFD\u200D♀️", + [":woman_running_tone4:"] = "\uD83C\uDFC3\uD83C\uDFFE\u200D♀️", + [":woman_running_tone5:"] = "\uD83C\uDFC3\uD83C\uDFFF\u200D♀️", + [":woman_scientist:"] = "\uD83D\uDC69\u200D\uD83D\uDD2C", + [":woman_scientist::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDD2C", + [":woman_scientist::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDD2C", + [":woman_scientist::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDD2C", + [":woman_scientist::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDD2C", + [":woman_scientist::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDD2C", + [":woman_scientist_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDD2C", + [":woman_scientist_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDD2C", + [":woman_scientist_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDD2C", + [":woman_scientist_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDD2C", + [":woman_scientist_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDD2C", + [":woman_scientist_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDD2C", + [":woman_scientist_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDD2C", + [":woman_scientist_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDD2C", + [":woman_scientist_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDD2C", + [":woman_scientist_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDD2C", + [":woman_shrugging:"] = "\uD83E\uDD37\u200D♀️", + [":woman_shrugging::skin-tone-1:"] = "\uD83E\uDD37\uD83C\uDFFB\u200D♀️", + [":woman_shrugging::skin-tone-2:"] = "\uD83E\uDD37\uD83C\uDFFC\u200D♀️", + [":woman_shrugging::skin-tone-3:"] = "\uD83E\uDD37\uD83C\uDFFD\u200D♀️", + [":woman_shrugging::skin-tone-4:"] = "\uD83E\uDD37\uD83C\uDFFE\u200D♀️", + [":woman_shrugging::skin-tone-5:"] = "\uD83E\uDD37\uD83C\uDFFF\u200D♀️", + [":woman_shrugging_dark_skin_tone:"] = "\uD83E\uDD37\uD83C\uDFFF\u200D♀️", + [":woman_shrugging_light_skin_tone:"] = "\uD83E\uDD37\uD83C\uDFFB\u200D♀️", + [":woman_shrugging_medium_dark_skin_tone:"] = "\uD83E\uDD37\uD83C\uDFFE\u200D♀️", + [":woman_shrugging_medium_light_skin_tone:"] = "\uD83E\uDD37\uD83C\uDFFC\u200D♀️", + [":woman_shrugging_medium_skin_tone:"] = "\uD83E\uDD37\uD83C\uDFFD\u200D♀️", + [":woman_shrugging_tone1:"] = "\uD83E\uDD37\uD83C\uDFFB\u200D♀️", + [":woman_shrugging_tone2:"] = "\uD83E\uDD37\uD83C\uDFFC\u200D♀️", + [":woman_shrugging_tone3:"] = "\uD83E\uDD37\uD83C\uDFFD\u200D♀️", + [":woman_shrugging_tone4:"] = "\uD83E\uDD37\uD83C\uDFFE\u200D♀️", + [":woman_shrugging_tone5:"] = "\uD83E\uDD37\uD83C\uDFFF\u200D♀️", + [":woman_singer:"] = "\uD83D\uDC69\u200D\uD83C\uDFA4", + [":woman_singer::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDFA4", + [":woman_singer::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDFA4", + [":woman_singer::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDFA4", + [":woman_singer::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDFA4", + [":woman_singer::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDFA4", + [":woman_singer_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDFA4", + [":woman_singer_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDFA4", + [":woman_singer_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDFA4", + [":woman_singer_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDFA4", + [":woman_singer_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDFA4", + [":woman_singer_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDFA4", + [":woman_singer_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDFA4", + [":woman_singer_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDFA4", + [":woman_singer_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDFA4", + [":woman_singer_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDFA4", + [":woman_standing:"] = "\uD83E\uDDCD\u200D♀️", + [":woman_standing::skin-tone-1:"] = "\uD83E\uDDCD\uD83C\uDFFB\u200D♀️", + [":woman_standing::skin-tone-2:"] = "\uD83E\uDDCD\uD83C\uDFFC\u200D♀️", + [":woman_standing::skin-tone-3:"] = "\uD83E\uDDCD\uD83C\uDFFD\u200D♀️", + [":woman_standing::skin-tone-4:"] = "\uD83E\uDDCD\uD83C\uDFFE\u200D♀️", + [":woman_standing::skin-tone-5:"] = "\uD83E\uDDCD\uD83C\uDFFF\u200D♀️", + [":woman_standing_dark_skin_tone:"] = "\uD83E\uDDCD\uD83C\uDFFF\u200D♀️", + [":woman_standing_light_skin_tone:"] = "\uD83E\uDDCD\uD83C\uDFFB\u200D♀️", + [":woman_standing_medium_dark_skin_tone:"] = "\uD83E\uDDCD\uD83C\uDFFE\u200D♀️", + [":woman_standing_medium_light_skin_tone:"] = "\uD83E\uDDCD\uD83C\uDFFC\u200D♀️", + [":woman_standing_medium_skin_tone:"] = "\uD83E\uDDCD\uD83C\uDFFD\u200D♀️", + [":woman_standing_tone1:"] = "\uD83E\uDDCD\uD83C\uDFFB\u200D♀️", + [":woman_standing_tone2:"] = "\uD83E\uDDCD\uD83C\uDFFC\u200D♀️", + [":woman_standing_tone3:"] = "\uD83E\uDDCD\uD83C\uDFFD\u200D♀️", + [":woman_standing_tone4:"] = "\uD83E\uDDCD\uD83C\uDFFE\u200D♀️", + [":woman_standing_tone5:"] = "\uD83E\uDDCD\uD83C\uDFFF\u200D♀️", + [":woman_student:"] = "\uD83D\uDC69\u200D\uD83C\uDF93", + [":woman_student::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDF93", + [":woman_student::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDF93", + [":woman_student::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDF93", + [":woman_student::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDF93", + [":woman_student::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDF93", + [":woman_student_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDF93", + [":woman_student_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDF93", + [":woman_student_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDF93", + [":woman_student_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDF93", + [":woman_student_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDF93", + [":woman_student_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDF93", + [":woman_student_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDF93", + [":woman_student_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDF93", + [":woman_student_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDF93", + [":woman_student_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDF93", + [":woman_superhero:"] = "\uD83E\uDDB8\u200D♀️", + [":woman_superhero::skin-tone-1:"] = "\uD83E\uDDB8\uD83C\uDFFB\u200D♀️", + [":woman_superhero::skin-tone-2:"] = "\uD83E\uDDB8\uD83C\uDFFC\u200D♀️", + [":woman_superhero::skin-tone-3:"] = "\uD83E\uDDB8\uD83C\uDFFD\u200D♀️", + [":woman_superhero::skin-tone-4:"] = "\uD83E\uDDB8\uD83C\uDFFE\u200D♀️", + [":woman_superhero::skin-tone-5:"] = "\uD83E\uDDB8\uD83C\uDFFF\u200D♀️", + [":woman_superhero_dark_skin_tone:"] = "\uD83E\uDDB8\uD83C\uDFFF\u200D♀️", + [":woman_superhero_light_skin_tone:"] = "\uD83E\uDDB8\uD83C\uDFFB\u200D♀️", + [":woman_superhero_medium_dark_skin_tone:"] = "\uD83E\uDDB8\uD83C\uDFFE\u200D♀️", + [":woman_superhero_medium_light_skin_tone:"] = "\uD83E\uDDB8\uD83C\uDFFC\u200D♀️", + [":woman_superhero_medium_skin_tone:"] = "\uD83E\uDDB8\uD83C\uDFFD\u200D♀️", + [":woman_superhero_tone1:"] = "\uD83E\uDDB8\uD83C\uDFFB\u200D♀️", + [":woman_superhero_tone2:"] = "\uD83E\uDDB8\uD83C\uDFFC\u200D♀️", + [":woman_superhero_tone3:"] = "\uD83E\uDDB8\uD83C\uDFFD\u200D♀️", + [":woman_superhero_tone4:"] = "\uD83E\uDDB8\uD83C\uDFFE\u200D♀️", + [":woman_superhero_tone5:"] = "\uD83E\uDDB8\uD83C\uDFFF\u200D♀️", + [":woman_supervillain:"] = "\uD83E\uDDB9\u200D♀️", + [":woman_supervillain::skin-tone-1:"] = "\uD83E\uDDB9\uD83C\uDFFB\u200D♀️", + [":woman_supervillain::skin-tone-2:"] = "\uD83E\uDDB9\uD83C\uDFFC\u200D♀️", + [":woman_supervillain::skin-tone-3:"] = "\uD83E\uDDB9\uD83C\uDFFD\u200D♀️", + [":woman_supervillain::skin-tone-4:"] = "\uD83E\uDDB9\uD83C\uDFFE\u200D♀️", + [":woman_supervillain::skin-tone-5:"] = "\uD83E\uDDB9\uD83C\uDFFF\u200D♀️", + [":woman_supervillain_dark_skin_tone:"] = "\uD83E\uDDB9\uD83C\uDFFF\u200D♀️", + [":woman_supervillain_light_skin_tone:"] = "\uD83E\uDDB9\uD83C\uDFFB\u200D♀️", + [":woman_supervillain_medium_dark_skin_tone:"] = "\uD83E\uDDB9\uD83C\uDFFE\u200D♀️", + [":woman_supervillain_medium_light_skin_tone:"] = "\uD83E\uDDB9\uD83C\uDFFC\u200D♀️", + [":woman_supervillain_medium_skin_tone:"] = "\uD83E\uDDB9\uD83C\uDFFD\u200D♀️", + [":woman_supervillain_tone1:"] = "\uD83E\uDDB9\uD83C\uDFFB\u200D♀️", + [":woman_supervillain_tone2:"] = "\uD83E\uDDB9\uD83C\uDFFC\u200D♀️", + [":woman_supervillain_tone3:"] = "\uD83E\uDDB9\uD83C\uDFFD\u200D♀️", + [":woman_supervillain_tone4:"] = "\uD83E\uDDB9\uD83C\uDFFE\u200D♀️", + [":woman_supervillain_tone5:"] = "\uD83E\uDDB9\uD83C\uDFFF\u200D♀️", + [":woman_surfing:"] = "\uD83C\uDFC4\u200D♀️", + [":woman_surfing::skin-tone-1:"] = "\uD83C\uDFC4\uD83C\uDFFB\u200D♀️", + [":woman_surfing::skin-tone-2:"] = "\uD83C\uDFC4\uD83C\uDFFC\u200D♀️", + [":woman_surfing::skin-tone-3:"] = "\uD83C\uDFC4\uD83C\uDFFD\u200D♀️", + [":woman_surfing::skin-tone-4:"] = "\uD83C\uDFC4\uD83C\uDFFE\u200D♀️", + [":woman_surfing::skin-tone-5:"] = "\uD83C\uDFC4\uD83C\uDFFF\u200D♀️", + [":woman_surfing_dark_skin_tone:"] = "\uD83C\uDFC4\uD83C\uDFFF\u200D♀️", + [":woman_surfing_light_skin_tone:"] = "\uD83C\uDFC4\uD83C\uDFFB\u200D♀️", + [":woman_surfing_medium_dark_skin_tone:"] = "\uD83C\uDFC4\uD83C\uDFFE\u200D♀️", + [":woman_surfing_medium_light_skin_tone:"] = "\uD83C\uDFC4\uD83C\uDFFC\u200D♀️", + [":woman_surfing_medium_skin_tone:"] = "\uD83C\uDFC4\uD83C\uDFFD\u200D♀️", + [":woman_surfing_tone1:"] = "\uD83C\uDFC4\uD83C\uDFFB\u200D♀️", + [":woman_surfing_tone2:"] = "\uD83C\uDFC4\uD83C\uDFFC\u200D♀️", + [":woman_surfing_tone3:"] = "\uD83C\uDFC4\uD83C\uDFFD\u200D♀️", + [":woman_surfing_tone4:"] = "\uD83C\uDFC4\uD83C\uDFFE\u200D♀️", + [":woman_surfing_tone5:"] = "\uD83C\uDFC4\uD83C\uDFFF\u200D♀️", + [":woman_swimming:"] = "\uD83C\uDFCA\u200D♀️", + [":woman_swimming::skin-tone-1:"] = "\uD83C\uDFCA\uD83C\uDFFB\u200D♀️", + [":woman_swimming::skin-tone-2:"] = "\uD83C\uDFCA\uD83C\uDFFC\u200D♀️", + [":woman_swimming::skin-tone-3:"] = "\uD83C\uDFCA\uD83C\uDFFD\u200D♀️", + [":woman_swimming::skin-tone-4:"] = "\uD83C\uDFCA\uD83C\uDFFE\u200D♀️", + [":woman_swimming::skin-tone-5:"] = "\uD83C\uDFCA\uD83C\uDFFF\u200D♀️", + [":woman_swimming_dark_skin_tone:"] = "\uD83C\uDFCA\uD83C\uDFFF\u200D♀️", + [":woman_swimming_light_skin_tone:"] = "\uD83C\uDFCA\uD83C\uDFFB\u200D♀️", + [":woman_swimming_medium_dark_skin_tone:"] = "\uD83C\uDFCA\uD83C\uDFFE\u200D♀️", + [":woman_swimming_medium_light_skin_tone:"] = "\uD83C\uDFCA\uD83C\uDFFC\u200D♀️", + [":woman_swimming_medium_skin_tone:"] = "\uD83C\uDFCA\uD83C\uDFFD\u200D♀️", + [":woman_swimming_tone1:"] = "\uD83C\uDFCA\uD83C\uDFFB\u200D♀️", + [":woman_swimming_tone2:"] = "\uD83C\uDFCA\uD83C\uDFFC\u200D♀️", + [":woman_swimming_tone3:"] = "\uD83C\uDFCA\uD83C\uDFFD\u200D♀️", + [":woman_swimming_tone4:"] = "\uD83C\uDFCA\uD83C\uDFFE\u200D♀️", + [":woman_swimming_tone5:"] = "\uD83C\uDFCA\uD83C\uDFFF\u200D♀️", + [":woman_teacher:"] = "\uD83D\uDC69\u200D\uD83C\uDFEB", + [":woman_teacher::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDFEB", + [":woman_teacher::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDFEB", + [":woman_teacher::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDFEB", + [":woman_teacher::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDFEB", + [":woman_teacher::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDFEB", + [":woman_teacher_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDFEB", + [":woman_teacher_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDFEB", + [":woman_teacher_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDFEB", + [":woman_teacher_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDFEB", + [":woman_teacher_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDFEB", + [":woman_teacher_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83C\uDFEB", + [":woman_teacher_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83C\uDFEB", + [":woman_teacher_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83C\uDFEB", + [":woman_teacher_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83C\uDFEB", + [":woman_teacher_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83C\uDFEB", + [":woman_technologist:"] = "\uD83D\uDC69\u200D\uD83D\uDCBB", + [":woman_technologist::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDCBB", + [":woman_technologist::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDCBB", + [":woman_technologist::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDCBB", + [":woman_technologist::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDCBB", + [":woman_technologist::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDCBB", + [":woman_technologist_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDCBB", + [":woman_technologist_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDCBB", + [":woman_technologist_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDCBB", + [":woman_technologist_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDCBB", + [":woman_technologist_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDCBB", + [":woman_technologist_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83D\uDCBB", + [":woman_technologist_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83D\uDCBB", + [":woman_technologist_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83D\uDCBB", + [":woman_technologist_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDCBB", + [":woman_technologist_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83D\uDCBB", + [":woman_tipping_hand:"] = "\uD83D\uDC81\u200D♀️", + [":woman_tipping_hand::skin-tone-1:"] = "\uD83D\uDC81\uD83C\uDFFB\u200D♀️", + [":woman_tipping_hand::skin-tone-2:"] = "\uD83D\uDC81\uD83C\uDFFC\u200D♀️", + [":woman_tipping_hand::skin-tone-3:"] = "\uD83D\uDC81\uD83C\uDFFD\u200D♀️", + [":woman_tipping_hand::skin-tone-4:"] = "\uD83D\uDC81\uD83C\uDFFE\u200D♀️", + [":woman_tipping_hand::skin-tone-5:"] = "\uD83D\uDC81\uD83C\uDFFF\u200D♀️", + [":woman_tipping_hand_dark_skin_tone:"] = "\uD83D\uDC81\uD83C\uDFFF\u200D♀️", + [":woman_tipping_hand_light_skin_tone:"] = "\uD83D\uDC81\uD83C\uDFFB\u200D♀️", + [":woman_tipping_hand_medium_dark_skin_tone:"] = "\uD83D\uDC81\uD83C\uDFFE\u200D♀️", + [":woman_tipping_hand_medium_light_skin_tone:"] = "\uD83D\uDC81\uD83C\uDFFC\u200D♀️", + [":woman_tipping_hand_medium_skin_tone:"] = "\uD83D\uDC81\uD83C\uDFFD\u200D♀️", + [":woman_tipping_hand_tone1:"] = "\uD83D\uDC81\uD83C\uDFFB\u200D♀️", + [":woman_tipping_hand_tone2:"] = "\uD83D\uDC81\uD83C\uDFFC\u200D♀️", + [":woman_tipping_hand_tone3:"] = "\uD83D\uDC81\uD83C\uDFFD\u200D♀️", + [":woman_tipping_hand_tone4:"] = "\uD83D\uDC81\uD83C\uDFFE\u200D♀️", + [":woman_tipping_hand_tone5:"] = "\uD83D\uDC81\uD83C\uDFFF\u200D♀️", + [":woman_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB", + [":woman_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC", + [":woman_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD", + [":woman_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE", + [":woman_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF", + [":woman_vampire:"] = "\uD83E\uDDDB\u200D♀️", + [":woman_vampire::skin-tone-1:"] = "\uD83E\uDDDB\uD83C\uDFFB\u200D♀️", + [":woman_vampire::skin-tone-2:"] = "\uD83E\uDDDB\uD83C\uDFFC\u200D♀️", + [":woman_vampire::skin-tone-3:"] = "\uD83E\uDDDB\uD83C\uDFFD\u200D♀️", + [":woman_vampire::skin-tone-4:"] = "\uD83E\uDDDB\uD83C\uDFFE\u200D♀️", + [":woman_vampire::skin-tone-5:"] = "\uD83E\uDDDB\uD83C\uDFFF\u200D♀️", + [":woman_vampire_dark_skin_tone:"] = "\uD83E\uDDDB\uD83C\uDFFF\u200D♀️", + [":woman_vampire_light_skin_tone:"] = "\uD83E\uDDDB\uD83C\uDFFB\u200D♀️", + [":woman_vampire_medium_dark_skin_tone:"] = "\uD83E\uDDDB\uD83C\uDFFE\u200D♀️", + [":woman_vampire_medium_light_skin_tone:"] = "\uD83E\uDDDB\uD83C\uDFFC\u200D♀️", + [":woman_vampire_medium_skin_tone:"] = "\uD83E\uDDDB\uD83C\uDFFD\u200D♀️", + [":woman_vampire_tone1:"] = "\uD83E\uDDDB\uD83C\uDFFB\u200D♀️", + [":woman_vampire_tone2:"] = "\uD83E\uDDDB\uD83C\uDFFC\u200D♀️", + [":woman_vampire_tone3:"] = "\uD83E\uDDDB\uD83C\uDFFD\u200D♀️", + [":woman_vampire_tone4:"] = "\uD83E\uDDDB\uD83C\uDFFE\u200D♀️", + [":woman_vampire_tone5:"] = "\uD83E\uDDDB\uD83C\uDFFF\u200D♀️", + [":woman_walking:"] = "\uD83D\uDEB6\u200D♀️", + [":woman_walking::skin-tone-1:"] = "\uD83D\uDEB6\uD83C\uDFFB\u200D♀️", + [":woman_walking::skin-tone-2:"] = "\uD83D\uDEB6\uD83C\uDFFC\u200D♀️", + [":woman_walking::skin-tone-3:"] = "\uD83D\uDEB6\uD83C\uDFFD\u200D♀️", + [":woman_walking::skin-tone-4:"] = "\uD83D\uDEB6\uD83C\uDFFE\u200D♀️", + [":woman_walking::skin-tone-5:"] = "\uD83D\uDEB6\uD83C\uDFFF\u200D♀️", + [":woman_walking_dark_skin_tone:"] = "\uD83D\uDEB6\uD83C\uDFFF\u200D♀️", + [":woman_walking_light_skin_tone:"] = "\uD83D\uDEB6\uD83C\uDFFB\u200D♀️", + [":woman_walking_medium_dark_skin_tone:"] = "\uD83D\uDEB6\uD83C\uDFFE\u200D♀️", + [":woman_walking_medium_light_skin_tone:"] = "\uD83D\uDEB6\uD83C\uDFFC\u200D♀️", + [":woman_walking_medium_skin_tone:"] = "\uD83D\uDEB6\uD83C\uDFFD\u200D♀️", + [":woman_walking_tone1:"] = "\uD83D\uDEB6\uD83C\uDFFB\u200D♀️", + [":woman_walking_tone2:"] = "\uD83D\uDEB6\uD83C\uDFFC\u200D♀️", + [":woman_walking_tone3:"] = "\uD83D\uDEB6\uD83C\uDFFD\u200D♀️", + [":woman_walking_tone4:"] = "\uD83D\uDEB6\uD83C\uDFFE\u200D♀️", + [":woman_walking_tone5:"] = "\uD83D\uDEB6\uD83C\uDFFF\u200D♀️", + [":woman_wearing_turban:"] = "\uD83D\uDC73\u200D♀️", + [":woman_wearing_turban::skin-tone-1:"] = "\uD83D\uDC73\uD83C\uDFFB\u200D♀️", + [":woman_wearing_turban::skin-tone-2:"] = "\uD83D\uDC73\uD83C\uDFFC\u200D♀️", + [":woman_wearing_turban::skin-tone-3:"] = "\uD83D\uDC73\uD83C\uDFFD\u200D♀️", + [":woman_wearing_turban::skin-tone-4:"] = "\uD83D\uDC73\uD83C\uDFFE\u200D♀️", + [":woman_wearing_turban::skin-tone-5:"] = "\uD83D\uDC73\uD83C\uDFFF\u200D♀️", + [":woman_wearing_turban_dark_skin_tone:"] = "\uD83D\uDC73\uD83C\uDFFF\u200D♀️", + [":woman_wearing_turban_light_skin_tone:"] = "\uD83D\uDC73\uD83C\uDFFB\u200D♀️", + [":woman_wearing_turban_medium_dark_skin_tone:"] = "\uD83D\uDC73\uD83C\uDFFE\u200D♀️", + [":woman_wearing_turban_medium_light_skin_tone:"] = "\uD83D\uDC73\uD83C\uDFFC\u200D♀️", + [":woman_wearing_turban_medium_skin_tone:"] = "\uD83D\uDC73\uD83C\uDFFD\u200D♀️", + [":woman_wearing_turban_tone1:"] = "\uD83D\uDC73\uD83C\uDFFB\u200D♀️", + [":woman_wearing_turban_tone2:"] = "\uD83D\uDC73\uD83C\uDFFC\u200D♀️", + [":woman_wearing_turban_tone3:"] = "\uD83D\uDC73\uD83C\uDFFD\u200D♀️", + [":woman_wearing_turban_tone4:"] = "\uD83D\uDC73\uD83C\uDFFE\u200D♀️", + [":woman_wearing_turban_tone5:"] = "\uD83D\uDC73\uD83C\uDFFF\u200D♀️", + [":woman_white_haired:"] = "\uD83D\uDC69\u200D\uD83E\uDDB3", + [":woman_white_haired::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDB3", + [":woman_white_haired::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDB3", + [":woman_white_haired::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDB3", + [":woman_white_haired::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDB3", + [":woman_white_haired::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDB3", + [":woman_white_haired_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDB3", + [":woman_white_haired_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDB3", + [":woman_white_haired_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDB3", + [":woman_white_haired_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDB3", + [":woman_white_haired_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDB3", + [":woman_white_haired_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDB3", + [":woman_white_haired_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDB3", + [":woman_white_haired_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDB3", + [":woman_white_haired_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDB3", + [":woman_white_haired_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDB3", + [":woman_with_headscarf:"] = "\uD83E\uDDD5", + [":woman_with_headscarf::skin-tone-1:"] = "\uD83E\uDDD5\uD83C\uDFFB", + [":woman_with_headscarf::skin-tone-2:"] = "\uD83E\uDDD5\uD83C\uDFFC", + [":woman_with_headscarf::skin-tone-3:"] = "\uD83E\uDDD5\uD83C\uDFFD", + [":woman_with_headscarf::skin-tone-4:"] = "\uD83E\uDDD5\uD83C\uDFFE", + [":woman_with_headscarf::skin-tone-5:"] = "\uD83E\uDDD5\uD83C\uDFFF", + [":woman_with_headscarf_dark_skin_tone:"] = "\uD83E\uDDD5\uD83C\uDFFF", + [":woman_with_headscarf_light_skin_tone:"] = "\uD83E\uDDD5\uD83C\uDFFB", + [":woman_with_headscarf_medium_dark_skin_tone:"] = "\uD83E\uDDD5\uD83C\uDFFE", + [":woman_with_headscarf_medium_light_skin_tone:"] = "\uD83E\uDDD5\uD83C\uDFFC", + [":woman_with_headscarf_medium_skin_tone:"] = "\uD83E\uDDD5\uD83C\uDFFD", + [":woman_with_headscarf_tone1:"] = "\uD83E\uDDD5\uD83C\uDFFB", + [":woman_with_headscarf_tone2:"] = "\uD83E\uDDD5\uD83C\uDFFC", + [":woman_with_headscarf_tone3:"] = "\uD83E\uDDD5\uD83C\uDFFD", + [":woman_with_headscarf_tone4:"] = "\uD83E\uDDD5\uD83C\uDFFE", + [":woman_with_headscarf_tone5:"] = "\uD83E\uDDD5\uD83C\uDFFF", + [":woman_with_probing_cane:"] = "\uD83D\uDC69\u200D\uD83E\uDDAF", + [":woman_with_probing_cane::skin-tone-1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDAF", + [":woman_with_probing_cane::skin-tone-2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDAF", + [":woman_with_probing_cane::skin-tone-3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDAF", + [":woman_with_probing_cane::skin-tone-4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDAF", + [":woman_with_probing_cane::skin-tone-5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDAF", + [":woman_with_probing_cane_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDAF", + [":woman_with_probing_cane_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDAF", + [":woman_with_probing_cane_medium_dark_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDAF", + [":woman_with_probing_cane_medium_light_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDAF", + [":woman_with_probing_cane_medium_skin_tone:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDAF", + [":woman_with_probing_cane_tone1:"] = "\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDDAF", + [":woman_with_probing_cane_tone2:"] = "\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDDAF", + [":woman_with_probing_cane_tone3:"] = "\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDDAF", + [":woman_with_probing_cane_tone4:"] = "\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDDAF", + [":woman_with_probing_cane_tone5:"] = "\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDDAF", + [":woman_zombie:"] = "\uD83E\uDDDF\u200D♀️", + [":womans_clothes:"] = "\uD83D\uDC5A", + [":womans_flat_shoe:"] = "\uD83E\uDD7F", + [":womans_hat:"] = "\uD83D\uDC52", + [":women_with_bunny_ears_partying:"] = "\uD83D\uDC6F\u200D♀️", + [":women_wrestling:"] = "\uD83E\uDD3C\u200D♀️", + [":womens:"] = "\uD83D\uDEBA", + [":woozy_face:"] = "\uD83E\uDD74", + [":world_map:"] = "\uD83D\uDDFA️", + [":worried:"] = "\uD83D\uDE1F", + [":worship_symbol:"] = "\uD83D\uDED0", + [":wrench:"] = "\uD83D\uDD27", + [":wrestlers:"] = "\uD83E\uDD3C", + [":wrestling:"] = "\uD83E\uDD3C", + [":writing_hand:"] = "✍️", + [":writing_hand::skin-tone-1:"] = "✍\uD83C\uDFFB", + [":writing_hand::skin-tone-2:"] = "✍\uD83C\uDFFC", + [":writing_hand::skin-tone-3:"] = "✍\uD83C\uDFFD", + [":writing_hand::skin-tone-4:"] = "✍\uD83C\uDFFE", + [":writing_hand::skin-tone-5:"] = "✍\uD83C\uDFFF", + [":writing_hand_tone1:"] = "✍\uD83C\uDFFB", + [":writing_hand_tone2:"] = "✍\uD83C\uDFFC", + [":writing_hand_tone3:"] = "✍\uD83C\uDFFD", + [":writing_hand_tone4:"] = "✍\uD83C\uDFFE", + [":writing_hand_tone5:"] = "✍\uD83C\uDFFF", + [":x:"] = "❌", + [":yarn:"] = "\uD83E\uDDF6", + [":yawning_face:"] = "\uD83E\uDD71", + [":yellow_circle:"] = "\uD83D\uDFE1", + [":yellow_heart:"] = "\uD83D\uDC9B", + [":yellow_square:"] = "\uD83D\uDFE8", + [":yen:"] = "\uD83D\uDCB4", + [":yin_yang:"] = "☯️", + [":yo_yo:"] = "\uD83E\uDE80", + [":yum:"] = "\uD83D\uDE0B", + [":z"] = "\uD83D\uDE12", + [":zany_face:"] = "\uD83E\uDD2A", + [":zap:"] = "⚡", + [":zebra:"] = "\uD83E\uDD93", + [":zero:"] = "0️⃣", + [":zipper_mouth:"] = "\uD83E\uDD10", + [":zipper_mouth_face:"] = "\uD83E\uDD10", + [":zombie:"] = "\uD83E\uDDDF", + [":zzz:"] = "\uD83D\uDCA4", + [":|"] = "\uD83D\uDE10", + [";("] = "\uD83D\uDE2D", + [";)"] = "\uD83D\uDE09", + [";-("] = "\uD83D\uDE2D", + [";-)"] = "\uD83D\uDE09", + [":("] = "\uD83D\uDE20", + [">:-("] = "\uD83D\uDE20", + [">=("] = "\uD83D\uDE20", + [">=-("] = "\uD83D\uDE20", + ["B-)"] = "\uD83D\uDE0E", + ["O:)"] = "\uD83D\uDE07", + ["O:-)"] = "\uD83D\uDE07", + ["O=)"] = "\uD83D\uDE07", + ["O=-)"] = "\uD83D\uDE07", + ["X-)"] = "\uD83D\uDE06", + ["]:("] = "\uD83D\uDC7F", + ["]:)"] = "\uD83D\uDE08", + ["]:-("] = "\uD83D\uDC7F", + ["]:-)"] = "\uD83D\uDE08", + ["]=("] = "\uD83D\uDC7F", + ["]=)"] = "\uD83D\uDE08", + ["]=-("] = "\uD83D\uDC7F", + ["]=-)"] = "\uD83D\uDE08", + ["o:)"] = "\uD83D\uDE07", + ["o:-)"] = "\uD83D\uDE07", + ["o=)"] = "\uD83D\uDE07", + ["o=-)"] = "\uD83D\uDE07", + ["x-)"] = "\uD83D\uDE06", + ["♡"] = "❤️" + }; + + private static IReadOnlyCollection _unicodes; + private static IReadOnlyCollection Unicodes + { + get + { + _unicodes ??= NamesAndUnicodes.Select(kvp => kvp.Value).ToImmutableHashSet(); + return _unicodes; + } + } + + private static IReadOnlyDictionary> _unicodesAndNames; + private static IReadOnlyDictionary> UnicodesAndNames + { + get + { + _unicodesAndNames ??= + NamesAndUnicodes + .GroupBy(kvp => kvp.Value) + .ToImmutableDictionary( + grouping => grouping.Key, + grouping => grouping.Select(kvp => kvp.Key) + .ToList() + .AsReadOnly() + ); + return _unicodesAndNames; + } + } + + public static implicit operator Emoji(string s) => Parse(s); } } diff --git a/src/Discord.Net.Core/Entities/Emotes/Emote.cs b/src/Discord.Net.Core/Entities/Emotes/Emote.cs index 6054b3f74..cd88f97cc 100644 --- a/src/Discord.Net.Core/Entities/Emotes/Emote.cs +++ b/src/Discord.Net.Core/Entities/Emotes/Emote.cs @@ -102,5 +102,7 @@ public static bool TryParse(string text, out Emote result) /// A string representing the raw presentation of the emote (e.g. <:thonkang:282745590985523200>). /// public override string ToString() => $"<{(Animated ? "a" : "")}:{Name}:{Id}>"; + + public static implicit operator Emote(string s) => Parse(s); } } diff --git a/src/Discord.Net.Core/Entities/Guilds/GuildFeature.cs b/src/Discord.Net.Core/Entities/Guilds/GuildFeature.cs new file mode 100644 index 000000000..e3c325227 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/GuildFeature.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + [Flags] + public enum GuildFeature + { + /// + /// The guild has no features. + /// + None = 0, + /// + /// The guild has access to set an animated guild icon. + /// + AnimatedIcon = 1 << 0, + /// + /// The guild has access to set a guild banner image. + /// + Banner = 1 << 1, + /// + /// The guild has access to use commerce features (i.e. create store channels). + /// + Commerce = 1 << 2, + /// + /// The guild can enable welcome screen, Membership Screening, stage channels and discovery, and receives community updates. + /// + Community = 1 << 3, + /// + /// The guild is able to be discovered in the directory. + /// + Discoverable = 1 << 4, + /// + /// The guild is able to be featured in the directory. + /// + Featureable = 1 << 5, + /// + /// The guild has access to set an invite splash background. + /// + InviteSplash = 1 << 6, + /// + /// The guild has enabled Membership Screening. + /// + MemberVerificationGateEnabled = 1 << 7, + /// + /// The guild has enabled monetization. + /// + MonetizationEnabled = 1 << 8, + /// + /// The guild has increased custom sticker slots. + /// + MoreStickers = 1 << 9, + /// + /// The guild has access to create news channels. + /// + News = 1 << 10, + /// + /// The guild is partnered. + /// + Partnered = 1 << 11, + /// + /// The guild can be previewed before joining via Membership Screening or the directory. + /// + PreviewEnabled = 1 << 12, + /// + /// The guild has access to create private threads. + /// + PrivateThreads = 1 << 13, + /// + /// The guild is able to set role icons. + /// + RoleIcons = 1 << 14, + /// + /// The guild has access to the seven day archive time for threads. + /// + SevenDayThreadArchive = 1 << 15, + /// + /// The guild has access to the three day archive time for threads. + /// + ThreeDayThreadArchive = 1 << 16, + /// + /// The guild has enabled ticketed events. + /// + TicketedEventsEnabled = 1 << 17, + /// + /// The guild has access to set a vanity URL. + /// + VanityUrl = 1 << 18, + /// + /// The guild is verified. + /// + Verified = 1 << 19, + /// + /// The guild has access to set 384kbps bitrate in voice (previously VIP voice servers). + /// + VIPRegions = 1 << 20, + /// + /// The guild has enabled the welcome screen. + /// + WelcomeScreenEnabled = 1 << 21, + } +} diff --git a/src/Discord.Net.Core/Entities/Guilds/GuildFeatures.cs b/src/Discord.Net.Core/Entities/Guilds/GuildFeatures.cs new file mode 100644 index 000000000..699e47cf3 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/GuildFeatures.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + public class GuildFeatures + { + /// + /// Gets the flags of recognized features for this guild. + /// + public GuildFeature Value { get; } + + /// + /// Gets a collection of experimental features for this guild. + /// + public IReadOnlyCollection Experimental { get; } + + + internal GuildFeatures(GuildFeature value, string[] experimental) + { + Value = value; + Experimental = experimental.ToImmutableArray(); + } + + public bool HasFeature(GuildFeature feature) + => Value.HasFlag(feature); + public bool HasFeature(string feature) + => Experimental.Contains(feature); + + internal void EnsureFeature(GuildFeature feature) + { + if (!HasFeature(feature)) + { + var vals = Enum.GetValues(typeof(GuildFeature)).Cast(); + + var missingValues = vals.Where(x => feature.HasFlag(x) && !Value.HasFlag(x)); + + throw new InvalidOperationException($"Missing required guild feature{(missingValues.Count() > 1 ? "s" : "")} {string.Join(", ", missingValues.Select(x => x.ToString()))} in order to execute this operation."); + } + } + } +} diff --git a/src/Discord.Net.Core/Entities/Guilds/GuildProperties.cs b/src/Discord.Net.Core/Entities/Guilds/GuildProperties.cs index 981e1198c..d50b2ac38 100644 --- a/src/Discord.Net.Core/Entities/Guilds/GuildProperties.cs +++ b/src/Discord.Net.Core/Entities/Guilds/GuildProperties.cs @@ -85,8 +85,9 @@ public class GuildProperties /// given that the has also been set. /// A value of will deny guild boost messages from being sent, and allow all /// other types of messages. - /// Refer to the extension methods and - /// to check if these system channel message types + /// Refer to the extension methods , + /// , , + /// and to check if these system channel message types /// are enabled, without the need to manipulate the logic of the flag. /// public Optional SystemChannelFlags { get; set; } @@ -108,5 +109,9 @@ public class GuildProperties /// the value of will be unused. /// public Optional PreferredCulture { get; set; } + /// + /// Gets or sets if the boost progress bar is enabled. + /// + public Optional IsBoostProgressBarEnabled { get; set; } } } diff --git a/src/Discord.Net.Core/Entities/Guilds/GuildScheduledEventPrivacyLevel.cs b/src/Discord.Net.Core/Entities/Guilds/GuildScheduledEventPrivacyLevel.cs new file mode 100644 index 000000000..87881104c --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/GuildScheduledEventPrivacyLevel.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents the privacy level of a guild scheduled event. + /// + public enum GuildScheduledEventPrivacyLevel + { + /// + /// The scheduled event is public and available in discovery. + /// + [Obsolete("This event type isn't supported yet! check back later.", true)] + Public = 1, + + /// + /// The scheduled event is only accessible to guild members. + /// + Private = 2, + } +} diff --git a/src/Discord.Net.Core/Entities/Guilds/GuildScheduledEventStatus.cs b/src/Discord.Net.Core/Entities/Guilds/GuildScheduledEventStatus.cs new file mode 100644 index 000000000..6e3aa1ab3 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/GuildScheduledEventStatus.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents the status of a guild event. + /// + public enum GuildScheduledEventStatus + { + /// + /// The event is scheduled for a set time. + /// + Scheduled = 1, + + /// + /// The event has started. + /// + Active = 2, + + /// + /// The event was completed. + /// + Completed = 3, + + /// + /// The event was canceled. + /// + Cancelled = 4, + } +} diff --git a/src/Discord.Net.Core/Entities/Guilds/GuildScheduledEventType.cs b/src/Discord.Net.Core/Entities/Guilds/GuildScheduledEventType.cs new file mode 100644 index 000000000..ad741eee1 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/GuildScheduledEventType.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents the type of a guild scheduled event. + /// + public enum GuildScheduledEventType + { + /// + /// The event doesn't have a set type. + /// + None = 0, + + /// + /// The event is set in a stage channel. + /// + Stage = 1, + + /// + /// The event is set in a voice channel. + /// + Voice = 2, + + /// + /// The event is set for somewhere externally from discord. + /// + External = 3, + } +} diff --git a/src/Discord.Net.Core/Entities/Guilds/GuildScheduledEventsProperties.cs b/src/Discord.Net.Core/Entities/Guilds/GuildScheduledEventsProperties.cs new file mode 100644 index 000000000..a3fd729e5 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/GuildScheduledEventsProperties.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Provides properties that are used to modify an with the specified changes. + /// + public class GuildScheduledEventsProperties + { + /// + /// Gets or sets the channel id of the event. + /// + public Optional ChannelId { get; set; } + + /// + /// Gets or sets the location of this event. + /// + public Optional Location { get; set; } + + /// + /// Gets or sets the name of the event. + /// + public Optional Name { get; set; } + + /// + /// Gets or sets the privacy level of the event. + /// + public Optional PrivacyLevel { get; set; } + + /// + /// Gets or sets the start time of the event. + /// + public Optional StartTime { get; set; } + /// + /// Gets or sets the end time of the event. + /// + public Optional EndTime { get; set; } + + /// + /// Gets or sets the description of the event. + /// + public Optional Description { get; set; } + + /// + /// Gets or sets the type of the event. + /// + public Optional Type { get; set; } + + /// + /// Gets or sets the status of the event. + /// + public Optional Status { get; set; } + } +} diff --git a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs index b8fd858df..ebf2ccd4a 100644 --- a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs +++ b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Threading.Tasks; namespace Discord @@ -199,12 +200,19 @@ public interface IGuild : IDeletable, ISnowflakeEntity /// IReadOnlyCollection Emotes { get; } /// - /// Gets a collection of all extra features added to this guild. + /// Gets a collection of all custom stickers for this guild. /// /// - /// A read-only collection of enabled features in this guild. + /// A read-only collection of all custom stickers for this guild. /// - IReadOnlyCollection Features { get; } + IReadOnlyCollection Stickers { get; } + /// + /// Gets the features for this guild. + /// + /// + /// A flags enum containing all the features for the guild. + /// + GuildFeatures Features { get; } /// /// Gets a collection of all roles in this guild. /// @@ -316,6 +324,14 @@ public interface IGuild : IDeletable, ISnowflakeEntity /// string PreferredLocale { get; } + /// + /// Gets the NSFW level of this guild. + /// + /// + /// The NSFW level of this guild. + /// + NsfwLevel NsfwLevel { get; } + /// /// Gets the preferred culture of this guild. /// @@ -323,6 +339,13 @@ public interface IGuild : IDeletable, ISnowflakeEntity /// The preferred culture information of this guild. /// CultureInfo PreferredCulture { get; } + /// + /// Gets whether the guild has the boost progress bar enabled. + /// + /// + /// if the boost progress bar is enabled; otherwise . + /// + bool IsBoostProgressBarEnabled { get; } /// /// Modifies this guild. @@ -522,6 +545,27 @@ public interface IGuild : IDeletable, ISnowflakeEntity /// Task GetVoiceChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); /// + /// Gets a stage channel in this guild. + /// + /// The snowflake identifier for the stage channel. + /// The that determines whether the object should be fetched from cache. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains the stage channel associated + /// with the specified ; if none is found. + /// + Task GetStageChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); + /// + /// Gets a collection of all stage channels in this guild. + /// + /// The that determines whether the object should be fetched from cache. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection of + /// stage channels found within this guild. + /// + Task> GetStageChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); + /// /// Gets the AFK voice channel in this guild. /// /// The that determines whether the object should be fetched from cache. @@ -572,15 +616,35 @@ public interface IGuild : IDeletable, ISnowflakeEntity /// Task GetRulesChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); /// - /// Gets the text channel channel where admins and moderators of Community guilds receive notices from Discord. + /// Gets the text channel where admins and moderators of Community guilds receive notices from Discord. /// /// The that determines whether the object should be fetched from cache. /// The options to be used when sending the request. /// - /// A task that represents the asynchronous get operation. The task result contains the text channel channel where + /// A task that represents the asynchronous get operation. The task result contains the text channel where /// admins and moderators of Community guilds receive notices from Discord; if none is set. /// Task GetPublicUpdatesChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); + /// + /// Gets a thread channel within this guild. + /// + /// The id of the thread channel. + /// The that determines whether the object should be fetched from cache. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains the thread channel. + /// + Task GetThreadChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); + /// + /// Gets a collection of all thread channels in this guild. + /// + /// The that determines whether the object should be fetched from cache. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection of + /// thread channels found within this guild. + /// + Task> GetThreadChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); /// /// Creates a new text channel in this guild. @@ -610,6 +674,17 @@ public interface IGuild : IDeletable, ISnowflakeEntity /// Task CreateVoiceChannelAsync(string name, Action func = null, RequestOptions options = null); /// + /// Creates a new stage channel in this guild. + /// + /// The new name for the stage channel. + /// The delegate containing the properties to be applied to the channel upon its creation. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the newly created + /// stage channel. + /// + Task CreateStageChannelAsync(string name, Action func = null, RequestOptions options = null); + /// /// Creates a new channel category in this guild. /// /// The new name for the category. @@ -703,6 +778,12 @@ public interface IGuild : IDeletable, ISnowflakeEntity /// A guild user associated with the specified ; if the user is already in the guild. Task AddGuildUserAsync(ulong userId, string accessToken, Action func = null, RequestOptions options = null); /// + /// Disconnects the user from its current voice channel. + /// + /// The user to disconnect. + /// A task that represents the asynchronous operation for disconnecting a user. + Task DisconnectAsync(IGuildUser user); + /// /// Gets a collection of all users in this guild. /// /// @@ -760,7 +841,7 @@ public interface IGuild : IDeletable, ISnowflakeEntity /// Downloads all users for this guild if the current list is incomplete. /// /// - /// This method downloads all users found within this guild throught the Gateway and caches them. + /// This method downloads all users found within this guild through the Gateway and caches them. /// /// /// A task that represents the asynchronous download operation. @@ -883,6 +964,15 @@ Task> GetAuditLogsAsync(int limit = DiscordC /// emote. /// Task ModifyEmoteAsync(GuildEmote emote, Action func, RequestOptions options = null); + + /// + /// Moves the user to the voice channel. + /// + /// The user to move. + /// the channel where the user gets moved to. + /// A task that represents the asynchronous operation for moving a user. + Task MoveAsync(IGuildUser user, IVoiceChannel targetChannel); + /// /// Deletes an existing from this guild. /// @@ -892,5 +982,174 @@ Task> GetAuditLogsAsync(int limit = DiscordC /// A task that represents the asynchronous removal operation. /// Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null); + + /// + /// Creates a new sticker in this guild. + /// + /// The name of the sticker. + /// The description of the sticker. + /// The tags of the sticker. + /// The image of the new emote. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the created sticker. + /// + Task CreateStickerAsync(string name, string description, IEnumerable tags, Image image, RequestOptions options = null); + + /// + /// Creates a new sticker in this guild. + /// + /// The name of the sticker. + /// The description of the sticker. + /// The tags of the sticker. + /// The path of the file to upload. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the created sticker. + /// + Task CreateStickerAsync(string name, string description, IEnumerable tags, string path, RequestOptions options = null); + + /// + /// Creates a new sticker in this guild. + /// + /// The name of the sticker. + /// The description of the sticker. + /// The tags of the sticker. + /// The stream containing the file data. + /// The name of the file with the extension, ex: image.png. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the created sticker. + /// + Task CreateStickerAsync(string name, string description, IEnumerable tags, Stream stream, string filename, RequestOptions options = null); + + /// + /// Gets a specific sticker within this guild. + /// + /// The id of the sticker to get. + /// The that determines whether the object should be fetched from cache. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains the sticker found with the + /// specified ; if none is found. + /// + Task GetStickerAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); + + /// + /// Gets a collection of all stickers within this guild. + /// + /// The that determines whether the object should be fetched from cache. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection + /// of stickers found within the guild. + /// + Task> GetStickersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); + + /// + /// Deletes a sticker within this guild. + /// + /// The sticker to delete. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous removal operation. + /// + Task DeleteStickerAsync(ICustomSticker sticker, RequestOptions options = null); + + /// + /// Gets a event within this guild. + /// + /// The id of the event. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. + /// + Task GetEventAsync(ulong id, RequestOptions options = null); + + /// + /// Gets a collection of events within this guild. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. + /// + Task> GetEventsAsync(RequestOptions options = null); + + /// + /// Creates an event within this guild. + /// + /// The name of the event. + /// The privacy level of the event. + /// The start time of the event. + /// The type of the event. + /// The description of the event. + /// The end time of the event. + /// + /// The channel id of the event. + /// + /// The event must have a type of or + /// in order to use this property. + /// + /// + /// A collection of speakers for the event. + /// The location of the event; links are supported + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous create operation. + /// + Task CreateEventAsync( + string name, + DateTimeOffset startTime, + GuildScheduledEventType type, + GuildScheduledEventPrivacyLevel privacyLevel = GuildScheduledEventPrivacyLevel.Private, + string description = null, + DateTimeOffset? endTime = null, + ulong? channelId = null, + string location = null, + RequestOptions options = null); + + /// + /// Gets this guilds application commands. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection + /// of application commands found within the guild. + /// + Task> GetApplicationCommandsAsync(RequestOptions options = null); + + /// + /// Gets an application command within this guild with the specified id. + /// + /// The id of the application command to get. + /// The that determines whether the object should be fetched from cache. + /// The options to be used when sending the request. + /// + /// A ValueTask that represents the asynchronous get operation. The task result contains a + /// if found, otherwise . + /// + Task GetApplicationCommandAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, + RequestOptions options = null); + + /// + /// Creates an application command within this guild. + /// + /// The properties to use when creating the command. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the command that was created. + /// + Task CreateApplicationCommandAsync(ApplicationCommandProperties properties, RequestOptions options = null); + + /// + /// Overwrites the application commands within this guild. + /// + /// A collection of properties to use when creating the commands. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains a collection of commands that was created. + /// + Task> BulkOverwriteApplicationCommandsAsync(ApplicationCommandProperties[] properties, + RequestOptions options = null); } } diff --git a/src/Discord.Net.Core/Entities/Guilds/IGuildScheduledEvent.cs b/src/Discord.Net.Core/Entities/Guilds/IGuildScheduledEvent.cs new file mode 100644 index 000000000..e50f4cc2b --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/IGuildScheduledEvent.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents a generic guild scheduled event. + /// + public interface IGuildScheduledEvent : IEntity + { + /// + /// Gets the guild this event is scheduled in. + /// + IGuild Guild { get; } + + /// + /// Gets the optional channel id where this event will be hosted. + /// + ulong? ChannelId { get; } + + /// + /// Gets the user who created the event. + /// + IUser Creator { get; } + + /// + /// Gets the name of the event. + /// + string Name { get; } + + /// + /// Gets the description of the event. + /// + /// + /// This field is when the event doesn't have a discription. + /// + string Description { get; } + + /// + /// Gets the start time of the event. + /// + DateTimeOffset StartTime { get; } + + /// + /// Gets the optional end time of the event. + /// + DateTimeOffset? EndTime { get; } + + /// + /// Gets the privacy level of the event. + /// + GuildScheduledEventPrivacyLevel PrivacyLevel { get; } + + /// + /// Gets the status of the event. + /// + GuildScheduledEventStatus Status { get; } + + /// + /// Gets the type of the event. + /// + GuildScheduledEventType Type { get; } + + /// + /// Gets the optional entity id of the event. The "entity" of the event + /// can be a stage instance event as is seperate from . + /// + ulong? EntityId { get; } + + /// + /// Gets the location of the event if the is external. + /// + string Location { get; } + + /// + /// Gets the user count of the event. + /// + int? UserCount { get; } + + /// + /// Starts the event. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous start operation. + /// + Task StartAsync(RequestOptions options = null); + /// + /// Ends or canceles the event. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous end operation. + /// + Task EndAsync(RequestOptions options = null); + + /// + /// Modifies the guild event. + /// + /// The delegate containing the properties to modify the event with. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous modification operation. + /// + Task ModifyAsync(Action func, RequestOptions options = null); + + /// + /// Deletes the current event. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous delete operation. + /// + Task DeleteAsync(RequestOptions options = null); + + /// + /// Gets a collection of N users interested in the event. + /// + /// + /// + /// The returned collection is an asynchronous enumerable object; one must call + /// to access the individual messages as a + /// collection. + /// + /// This method will attempt to fetch all users that are interested in the event. + /// The library will attempt to split up the requests according to and . + /// In other words, if there are 300 users, and the constant + /// is 100, the request will be split into 3 individual requests; thus returning 3 individual asynchronous + /// responses, hence the need of flattening. + /// + /// The options to be used when sending the request. + /// + /// Paged collection of users. + /// + IAsyncEnumerable> GetUsersAsync(RequestOptions options = null); + + /// + /// Gets a collection of N users interested in the event. + /// + /// + /// + /// The returned collection is an asynchronous enumerable object; one must call + /// to access the individual users as a + /// collection. + /// + /// + /// Do not fetch too many users at once! This may cause unwanted preemptive rate limit or even actual + /// rate limit, causing your bot to freeze! + /// + /// This method will attempt to fetch the number of users specified under around + /// the user depending on the . The library will + /// attempt to split up the requests according to your and + /// . In other words, should the user request 500 users, + /// and the constant is 100, the request will + /// be split into 5 individual requests; thus returning 5 individual asynchronous responses, hence the need + /// of flattening. + /// + /// The ID of the starting user to get the users from. + /// The direction of the users to be gotten from. + /// The numbers of users to be gotten from. + /// The options to be used when sending the request. + /// + /// Paged collection of users. + /// + IAsyncEnumerable> GetUsersAsync(ulong fromUserId, Direction dir, int limit = DiscordConfig.MaxGuildEventUsersPerBatch, RequestOptions options = null); + } +} diff --git a/src/Discord.Net.Core/Entities/Guilds/NsfwLevel.cs b/src/Discord.Net.Core/Entities/Guilds/NsfwLevel.cs new file mode 100644 index 000000000..e3ac345d9 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Guilds/NsfwLevel.cs @@ -0,0 +1,22 @@ +namespace Discord +{ + public enum NsfwLevel + { + /// + /// Default or unset. + /// + Default = 0, + /// + /// Guild has extremely suggestive or mature content that would only be suitable for users 18 or over. + /// + Explicit = 1, + /// + /// Guild has no content that could be deemed NSFW; in other words, SFW. + /// + Safe = 2, + /// + /// Guild has mildly NSFW content that may not be suitable for users under 18. + /// + AgeRestricted = 3 + } +} \ No newline at end of file diff --git a/src/Discord.Net.Core/Entities/Guilds/SystemChannelMessageDeny.cs b/src/Discord.Net.Core/Entities/Guilds/SystemChannelMessageDeny.cs index 3f69693d0..06de7b812 100644 --- a/src/Discord.Net.Core/Entities/Guilds/SystemChannelMessageDeny.cs +++ b/src/Discord.Net.Core/Entities/Guilds/SystemChannelMessageDeny.cs @@ -17,6 +17,14 @@ public enum SystemChannelMessageDeny /// /// Deny the messages that are sent when a user boosts the guild. /// - GuildBoost = 0b10 + GuildBoost = 0b10, + /// + /// Deny the messages that are related to guild setup. + /// + GuildSetupTip = 0b100, + /// + /// Deny the reply with sticker button on welcome messages. + /// + WelcomeMessageReply = 0b1000 } } diff --git a/src/Discord.Net.Core/Entities/IApplication.cs b/src/Discord.Net.Core/Entities/IApplication.cs index 2174baff9..9f9881340 100644 --- a/src/Discord.Net.Core/Entities/IApplication.cs +++ b/src/Discord.Net.Core/Entities/IApplication.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + namespace Discord { /// @@ -16,8 +18,16 @@ public interface IApplication : ISnowflakeEntity /// /// Gets the RPC origins of the application. /// - string[] RPCOrigins { get; } - ulong Flags { get; } + IReadOnlyCollection RPCOrigins { get; } + ApplicationFlags Flags { get; } + /// + /// Gets a collection of install parameters for this application. + /// + ApplicationInstallParams InstallParams { get; } + /// + /// Gets a collection of tags related to the application. + /// + IReadOnlyCollection Tags { get; } /// /// Gets the icon URL of the application. /// diff --git a/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs new file mode 100644 index 000000000..9a69d9d18 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace Discord +{ + /// + /// Represents a for making slash commands. + /// + public class ApplicationCommandOptionProperties + { + private string _name; + private string _description; + + /// + /// Gets or sets the name of this option. + /// + public string Name + { + get => _name; + set + { + if (value == null) + throw new ArgumentNullException(nameof(value), $"{nameof(Name)} cannot be null."); + + if (value.Length > 32) + throw new ArgumentOutOfRangeException(nameof(value), "Name length must be less than or equal to 32."); + + if (!Regex.IsMatch(value, @"^[\w-]{1,32}$")) + throw new FormatException($"{nameof(value)} must match the regex ^[\\w-]{{1,32}}$"); + + _name = value; + } + } + + /// + /// Gets or sets the description of this option. + /// + public string Description + { + get => _description; + set => _description = value?.Length switch + { + > 100 => throw new ArgumentOutOfRangeException(nameof(value), "Description length must be less than or equal to 100."), + 0 => throw new ArgumentOutOfRangeException(nameof(value), "Description length must be at least 1."), + _ => value + }; + } + + /// + /// Gets or sets the type of this option. + /// + public ApplicationCommandOptionType Type { get; set; } + + /// + /// Gets or sets whether or not this options is the first required option for the user to complete. only one option can be default. + /// + public bool? IsDefault { get; set; } + + /// + /// Gets or sets if the option is required. + /// + public bool? IsRequired { get; set; } + + /// + /// Gets or sets whether or not this option supports autocomplete. + /// + public bool IsAutocomplete { get; set; } + + /// + /// Gets or sets the smallest number value the user can input. + /// + public double? MinValue { get; set; } + + /// + /// Gets or sets the largest number value the user can input. + /// + public double? MaxValue { get; set; } + + /// + /// Gets or sets the choices for string and int types for the user to pick from. + /// + public List Choices { get; set; } + + /// + /// Gets or sets if this option is a subcommand or subcommand group type, these nested options will be the parameters. + /// + public List Options { get; set; } + + /// + /// Gets or sets the allowed channel types for this option. + /// + public List ChannelTypes { get; set; } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionChoice.cs b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionChoice.cs new file mode 100644 index 000000000..6a908b075 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionChoice.cs @@ -0,0 +1,44 @@ +using System; + +namespace Discord +{ + /// + /// Represents a choice for a . This class is used when making new commands. + /// + public class ApplicationCommandOptionChoiceProperties + { + private string _name; + private object _value; + + /// + /// Gets or sets the name of this choice. + /// + public string Name + { + get => _name; + set => _name = value?.Length switch + { + > 100 => throw new ArgumentOutOfRangeException(nameof(value), "Name length must be less than or equal to 100."), + 0 => throw new ArgumentOutOfRangeException(nameof(value), "Name length must at least 1."), + _ => value + }; + } + + /// + /// Gets the value of this choice. + /// + /// Discord only accepts int, double/floats, and string as the input. + /// + /// + public object Value + { + get => _value; + set + { + if (value != null && value is not string && !value.IsNumericType()) + throw new ArgumentException("The value of a choice must be a string or a numeric type!"); + _value = value; + } + } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionType.cs b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionType.cs new file mode 100644 index 000000000..0f919f1f6 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionType.cs @@ -0,0 +1,58 @@ +namespace Discord +{ + /// + /// The option type of the Slash command parameter, See the discord docs. + /// + public enum ApplicationCommandOptionType : byte + { + /// + /// A sub command. + /// + SubCommand = 1, + + /// + /// A group of sub commands. + /// + SubCommandGroup = 2, + + /// + /// A of text. + /// + String = 3, + + /// + /// An . + /// + Integer = 4, + + /// + /// A . + /// + Boolean = 5, + + /// + /// A . + /// + User = 6, + + /// + /// A . + /// + Channel = 7, + + /// + /// A . + /// + Role = 8, + + /// + /// A or . + /// + Mentionable = 9, + + /// + /// A . + /// + Number = 10 + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandProperties.cs b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandProperties.cs new file mode 100644 index 000000000..501a0e905 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandProperties.cs @@ -0,0 +1,22 @@ +namespace Discord +{ + /// + /// Represents the base class to create/modify application commands. + /// + public abstract class ApplicationCommandProperties + { + internal abstract ApplicationCommandType Type { get; } + + /// + /// Gets or sets the name of this command. + /// + public Optional Name { get; set; } + + /// + /// Gets or sets whether the command is enabled by default when the app is added to a guild. Default is + /// + public Optional IsDefaultPermission { get; set; } + + internal ApplicationCommandProperties() { } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandTypes.cs b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandTypes.cs new file mode 100644 index 000000000..8cd31a420 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/ApplicationCommandTypes.cs @@ -0,0 +1,23 @@ +namespace Discord +{ + /// + /// Represents the types of application commands. + /// + public enum ApplicationCommandType : byte + { + /// + /// A Slash command type + /// + Slash = 1, + + /// + /// A Context Menu User command type + /// + User = 2, + + /// + /// A Context Menu Message command type + /// + Message = 3 + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/AutocompleteOption.cs b/src/Discord.Net.Core/Entities/Interactions/AutocompleteOption.cs new file mode 100644 index 000000000..eb22a9d27 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/AutocompleteOption.cs @@ -0,0 +1,36 @@ +namespace Discord +{ + /// + /// Represents an autocomplete option. + /// + public class AutocompleteOption + { + /// + /// Gets the type of this option. + /// + public ApplicationCommandOptionType Type { get; } + + /// + /// Gets the name of the option. + /// + public string Name { get; } + + /// + /// Gets the value of the option. + /// + public object Value { get; } + + /// + /// Gets whether or not this option is focused by the executing user. + /// + public bool Focused { get; } + + internal AutocompleteOption(ApplicationCommandOptionType type, string name, object value, bool focused) + { + Type = type; + Name = name; + Value = value; + Focused = focused; + } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/AutocompleteResult.cs b/src/Discord.Net.Core/Entities/Interactions/AutocompleteResult.cs new file mode 100644 index 000000000..0603a5a50 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/AutocompleteResult.cs @@ -0,0 +1,73 @@ +using System; + +namespace Discord +{ + /// + /// Represents a result to an autocomplete interaction. + /// + public class AutocompleteResult + { + private object _value; + private string _name; + + /// + /// Gets or sets the name of the result. + /// + /// + /// Name cannot be null and has to be between 1-100 characters in length. + /// + /// + /// + public string Name + { + get => _name; + set + { + if (value == null) + throw new ArgumentNullException(nameof(value), $"{nameof(Name)} cannot be null."); + _name = value.Length switch + { + > 100 => throw new ArgumentOutOfRangeException(nameof(value), "Name length must be less than or equal to 100."), + 0 => throw new ArgumentOutOfRangeException(nameof(value), "Name length must be at least 1."), + _ => value + }; + } + } + + /// + /// Gets or sets the value of the result. + /// + /// + /// Only , , and are allowed for a value. + /// + /// + /// + public object Value + { + get => _value; + set + { + if (value is not string && !value.IsNumericType()) + throw new ArgumentException($"{nameof(value)} must be a numeric type or a string!"); + + _value = value; + } + } + + /// + /// Creates a new . + /// + public AutocompleteResult() { } + + /// + /// Creates a new with the passed in and . + /// + /// + /// + public AutocompleteResult(string name, object value) + { + Name = name; + Value = value; + } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/ContextMenus/IMessageCommandInteraction.cs b/src/Discord.Net.Core/Entities/Interactions/ContextMenus/IMessageCommandInteraction.cs new file mode 100644 index 000000000..b1b331e8b --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/ContextMenus/IMessageCommandInteraction.cs @@ -0,0 +1,13 @@ +namespace Discord +{ + /// + /// Represents a Message Command interaction. + /// + public interface IMessageCommandInteraction : IDiscordInteraction + { + /// + /// Gets the data associated with this interaction. + /// + new IMessageCommandInteractionData Data { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/ContextMenus/IMessageCommandInteractionData.cs b/src/Discord.Net.Core/Entities/Interactions/ContextMenus/IMessageCommandInteractionData.cs new file mode 100644 index 000000000..311eef2d6 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/ContextMenus/IMessageCommandInteractionData.cs @@ -0,0 +1,13 @@ +namespace Discord +{ + /// + /// Represents the data tied with the interaction. + /// + public interface IMessageCommandInteractionData : IApplicationCommandInteractionData + { + /// + /// Gets the message associated with this message command. + /// + IMessage Message { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/ContextMenus/IUserCommandInteraction.cs b/src/Discord.Net.Core/Entities/Interactions/ContextMenus/IUserCommandInteraction.cs new file mode 100644 index 000000000..f7cfd67f0 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/ContextMenus/IUserCommandInteraction.cs @@ -0,0 +1,13 @@ +namespace Discord +{ + /// + /// Represents a User Command interaction. + /// + public interface IUserCommandInteraction : IDiscordInteraction + { + /// + /// Gets the data associated with this interaction. + /// + new IUserCommandInteractionData Data { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/ContextMenus/IUserCommandInteractionData.cs b/src/Discord.Net.Core/Entities/Interactions/ContextMenus/IUserCommandInteractionData.cs new file mode 100644 index 000000000..36e482ec9 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/ContextMenus/IUserCommandInteractionData.cs @@ -0,0 +1,13 @@ +namespace Discord +{ + /// + /// Represents the data tied with the interaction. + /// + public interface IUserCommandInteractionData : IApplicationCommandInteractionData + { + /// + /// Gets the user who this command targets. + /// + IUser User { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/ContextMenus/MessageCommandBuilder.cs b/src/Discord.Net.Core/Entities/Interactions/ContextMenus/MessageCommandBuilder.cs new file mode 100644 index 000000000..c7a7cf741 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/ContextMenus/MessageCommandBuilder.cs @@ -0,0 +1,77 @@ +namespace Discord +{ + /// + /// A class used to build Message commands. + /// + public class MessageCommandBuilder + { + /// + /// Returns the maximum length a commands name allowed by Discord + /// + public const int MaxNameLength = 32; + + /// + /// Gets or sets the name of this Message command. + /// + public string Name + { + get => _name; + set + { + Preconditions.NotNullOrEmpty(value, nameof(Name)); + Preconditions.AtLeast(value.Length, 1, nameof(Name)); + Preconditions.AtMost(value.Length, MaxNameLength, nameof(Name)); + + _name = value; + } + } + + /// + /// Gets or sets whether the command is enabled by default when the app is added to a guild + /// + public bool IsDefaultPermission { get; set; } = true; + + private string _name; + + /// + /// Build the current builder into a class. + /// + /// + /// A that can be used to create message commands. + /// + public MessageCommandProperties Build() + { + var props = new MessageCommandProperties + { + Name = Name, + IsDefaultPermission = IsDefaultPermission + }; + + return props; + } + + /// + /// Sets the field name. + /// + /// The value to set the field name to. + /// + /// The current builder. + /// + public MessageCommandBuilder WithName(string name) + { + Name = name; + return this; + } + + /// + /// Sets the default permission of the current command. + /// + /// The default permission value to set. + /// The current builder. + public MessageCommandBuilder WithDefaultPermission(bool isDefaultPermission) + { + IsDefaultPermission = isDefaultPermission; + return this; + } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/ContextMenus/MessageCommandProperties.cs b/src/Discord.Net.Core/Entities/Interactions/ContextMenus/MessageCommandProperties.cs new file mode 100644 index 000000000..356ed23d6 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/ContextMenus/MessageCommandProperties.cs @@ -0,0 +1,10 @@ +namespace Discord +{ + /// + /// A class used to create message commands. + /// + public class MessageCommandProperties : ApplicationCommandProperties + { + internal override ApplicationCommandType Type => ApplicationCommandType.Message; + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/ContextMenus/UserCommandBuilder.cs b/src/Discord.Net.Core/Entities/Interactions/ContextMenus/UserCommandBuilder.cs new file mode 100644 index 000000000..bd1078be3 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/ContextMenus/UserCommandBuilder.cs @@ -0,0 +1,75 @@ +namespace Discord +{ + /// + /// A class used to build user commands. + /// + public class UserCommandBuilder + { + /// + /// Returns the maximum length a commands name allowed by Discord. + /// + public const int MaxNameLength = 32; + + /// + /// Gets or sets the name of this User command. + /// + public string Name + { + get => _name; + set + { + Preconditions.NotNullOrEmpty(value, nameof(Name)); + Preconditions.AtLeast(value.Length, 1, nameof(Name)); + Preconditions.AtMost(value.Length, MaxNameLength, nameof(Name)); + + _name = value; + } + } + + /// + /// Gets or sets whether the command is enabled by default when the app is added to a guild. + /// + public bool IsDefaultPermission { get; set; } = true; + + private string _name; + + /// + /// Build the current builder into a class. + /// + /// A that can be used to create user commands. + public UserCommandProperties Build() + { + var props = new UserCommandProperties + { + Name = Name, + IsDefaultPermission = IsDefaultPermission + }; + + return props; + } + + /// + /// Sets the field name. + /// + /// The value to set the field name to. + /// + /// The current builder. + /// + public UserCommandBuilder WithName(string name) + { + Name = name; + return this; + } + + /// + /// Sets the default permission of the current command. + /// + /// The default permission value to set. + /// The current builder. + public UserCommandBuilder WithDefaultPermission(bool isDefaultPermission) + { + IsDefaultPermission = isDefaultPermission; + return this; + } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/ContextMenus/UserCommandProperties.cs b/src/Discord.Net.Core/Entities/Interactions/ContextMenus/UserCommandProperties.cs new file mode 100644 index 000000000..c42e916d9 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/ContextMenus/UserCommandProperties.cs @@ -0,0 +1,10 @@ +namespace Discord +{ + /// + /// A class used to create User commands. + /// + public class UserCommandProperties : ApplicationCommandProperties + { + internal override ApplicationCommandType Type => ApplicationCommandType.User; + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs b/src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs new file mode 100644 index 000000000..72045a52a --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// The base command model that belongs to an application. + /// + public interface IApplicationCommand : ISnowflakeEntity, IDeletable + { + /// + /// Gets the unique id of the parent application. + /// + ulong ApplicationId { get; } + + /// + /// Gets the type of the command. + /// + ApplicationCommandType Type { get; } + + /// + /// Gets the name of the command. + /// + string Name { get; } + + /// + /// Gets the description of the command. + /// + string Description { get; } + + /// + /// Gets whether the command is enabled by default when the app is added to a guild. + /// + bool IsDefaultPermission { get; } + + /// + /// Gets a collection of options for this application command. + /// + IReadOnlyCollection Options { get; } + + /// + /// Modifies the current application command. + /// + /// The new properties to use when modifying the command. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous modification operation. + /// + Task ModifyAsync(Action func, RequestOptions options = null); + + /// + /// Modifies the current application command. + /// + /// The new properties to use when modifying the command. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous modification operation. + /// + /// Thrown when you pass in an invalid type. + Task ModifyAsync(Action func, RequestOptions options = null) + where TArg : ApplicationCommandProperties; + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/IApplicationCommandInteractionData.cs b/src/Discord.Net.Core/Entities/Interactions/IApplicationCommandInteractionData.cs new file mode 100644 index 000000000..428f20fb6 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/IApplicationCommandInteractionData.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace Discord +{ + /// + /// Represents data of an Interaction Command, see . + /// + public interface IApplicationCommandInteractionData : IDiscordInteractionData + { + /// + /// Gets the snowflake id of this command. + /// + ulong Id { get; } + + /// + /// Gets the name of this command. + /// + string Name { get; } + + /// + /// Gets the options that the user has provided. + /// + IReadOnlyCollection Options { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/IApplicationCommandInteractionDataOption.cs b/src/Discord.Net.Core/Entities/Interactions/IApplicationCommandInteractionDataOption.cs new file mode 100644 index 000000000..072d2b32b --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/IApplicationCommandInteractionDataOption.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; + +namespace Discord +{ + /// + /// Represents a option group for a command. + /// + public interface IApplicationCommandInteractionDataOption + { + /// + /// Gets the name of the parameter. + /// + string Name { get; } + + /// + /// Gets the value of the pair. + /// + /// This objects type can be any one of the option types in . + /// + /// + object Value { get; } + + /// + /// Gets the type of this data's option. + /// + ApplicationCommandOptionType Type { get; } + + /// + /// Gets the nested options of this option. + /// + IReadOnlyCollection Options { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/IApplicationCommandOption.cs b/src/Discord.Net.Core/Entities/Interactions/IApplicationCommandOption.cs new file mode 100644 index 000000000..440c4bd6b --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/IApplicationCommandOption.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; + +namespace Discord +{ + /// + /// Options for the . + /// + public interface IApplicationCommandOption + { + /// + /// Gets the type of this . + /// + ApplicationCommandOptionType Type { get; } + + /// + /// Gets the name of this command option. + /// + string Name { get; } + + /// + /// Gets the description of this command option. + /// + string Description { get; } + + /// + /// Gets whether or not this is the first required option for the user to complete. + /// + bool? IsDefault { get; } + + /// + /// Gets whether or not the parameter is required or optional. + /// + bool? IsRequired { get; } + + /// + /// Gets the smallest number value the user can input. + /// + double? MinValue { get; } + + /// + /// Gets the largest number value the user can input. + /// + double? MaxValue { get; } + + /// + /// Gets the choices for string and int types for the user to pick from. + /// + IReadOnlyCollection Choices { get; } + + /// + /// Gets the sub-options for this command option. + /// + IReadOnlyCollection Options { get; } + + /// + /// Gets the allowed channel types for this option. + /// + IReadOnlyCollection ChannelTypes { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/IApplicationCommandOptionChoice.cs b/src/Discord.Net.Core/Entities/Interactions/IApplicationCommandOptionChoice.cs new file mode 100644 index 000000000..631706c6f --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/IApplicationCommandOptionChoice.cs @@ -0,0 +1,18 @@ +namespace Discord +{ + /// + /// Specifies choices for command group. + /// + public interface IApplicationCommandOptionChoice + { + /// + /// Gets the choice name. + /// + string Name { get; } + + /// + /// Gets the value of the choice. + /// + object Value { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/IDiscordInteraction.cs b/src/Discord.Net.Core/Entities/Interactions/IDiscordInteraction.cs new file mode 100644 index 000000000..d9e250118 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/IDiscordInteraction.cs @@ -0,0 +1,90 @@ +using System; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents a discord interaction. + /// + public interface IDiscordInteraction : ISnowflakeEntity + { + /// + /// Gets the id of the interaction. + /// + new ulong Id { get; } + + /// + /// Gets the type of this . + /// + InteractionType Type { get; } + + /// + /// Gets the data sent within this interaction. + /// + IDiscordInteractionData Data { get; } + + /// + /// Gets the continuation token for responding to the interaction. + /// + string Token { get; } + + /// + /// Gets the version of the interaction, always 1. + /// + int Version { get; } + + /// + /// Responds to an Interaction with type . + /// + /// The text of the message to be sent. + /// A array of embeds to send with this response. Max 10. + /// if the message should be read out by a text-to-speech reader, otherwise . + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . + /// The allowed mentions for this response. + /// The request options for this response. + /// A to be sent with this response. + /// A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + Task RespondAsync(string text = null, Embed[] embeds = null, bool isTTS = false, + bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null); + + /// + /// Sends a followup message for this interaction. + /// + /// The text of the message to be sent. + /// A array of embeds to send with this response. Max 10. + /// if the message should be read out by a text-to-speech reader, otherwise . + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . + /// The allowed mentions for this response. + /// The request options for this response. + /// A to be sent with this response. + /// A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + /// + /// The sent message. + /// + Task FollowupAsync(string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, + AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null); + + /// + /// Gets the original response for this interaction. + /// + /// The request options for this request. + /// A that represents the initial response. + Task GetOriginalResponseAsync(RequestOptions options = null); + + /// + /// Edits original response for this interaction. + /// + /// A delegate containing the properties to modify the message with. + /// The request options for this request. + /// A that represents the initial response. + Task ModifyOriginalResponseAsync(Action func, RequestOptions options = null); + + /// + /// Acknowledges this interaction. + /// + /// + /// A task that represents the asynchronous operation of acknowledging the interaction. + /// + Task DeferAsync(bool ephemeral = false, RequestOptions options = null); + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/IDiscordInteractionData.cs b/src/Discord.Net.Core/Entities/Interactions/IDiscordInteractionData.cs new file mode 100644 index 000000000..42b95738e --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/IDiscordInteractionData.cs @@ -0,0 +1,7 @@ +namespace Discord +{ + /// + /// Represents an interface used to specify classes that they are a valid data type of a class. + /// + public interface IDiscordInteractionData { } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs b/src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs new file mode 100644 index 000000000..ebdf29781 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/InteractionResponseType.cs @@ -0,0 +1,46 @@ +using System; + +namespace Discord +{ + /// + /// The response type for an . + /// + /// + /// After receiving an interaction, you must respond to acknowledge it. You can choose to respond with a message immediately using + /// or you can choose to send a deferred response with . If choosing a deferred response, the user will see a loading state for the interaction, + /// and you'll have up to 15 minutes to edit the original deferred response using Edit Original Interaction Response. + /// You can read more about Response types Here. + /// + public enum InteractionResponseType : byte + { + /// + /// ACK a Ping. + /// + Pong = 1, + + /// + /// Respond to an interaction with a message. + /// + ChannelMessageWithSource = 4, + + /// + /// ACK an interaction and edit a response later, the user sees a loading state. + /// + DeferredChannelMessageWithSource = 5, + + /// + /// For components: ACK an interaction and edit the original message later; the user does not see a loading state. + /// + DeferredUpdateMessage = 6, + + /// + /// For components: edit the message the component was attached to. + /// + UpdateMessage = 7, + + /// + /// Respond with a set of choices to a autocomplete interaction. + /// + ApplicationCommandAutocompleteResult = 8 + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/InteractionType.cs b/src/Discord.Net.Core/Entities/Interactions/InteractionType.cs new file mode 100644 index 000000000..e09c906b5 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/InteractionType.cs @@ -0,0 +1,28 @@ +namespace Discord +{ + /// + /// Represents a type of Interaction from discord. + /// + public enum InteractionType : byte + { + /// + /// A ping from discord. + /// + Ping = 1, + + /// + /// A sent from discord. + /// + ApplicationCommand = 2, + + /// + /// A sent from discord. + /// + MessageComponent = 3, + + /// + /// An autocomplete request sent from discord. + /// + ApplicationCommandAutocomplete = 4 + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ActionRowComponent.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ActionRowComponent.cs new file mode 100644 index 000000000..202a5687f --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ActionRowComponent.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; + +namespace Discord +{ + /// + /// Represents a Row for child components to live in. + /// + public class ActionRowComponent : IMessageComponent + { + /// + public ComponentType Type => ComponentType.ActionRow; + + /// + /// Gets the child components in this row. + /// + public IReadOnlyCollection Components { get; internal set; } + + internal ActionRowComponent() { } + + internal ActionRowComponent(List components) + { + Components = components; + } + + string IMessageComponent.CustomId => null; + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ButtonComponent.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ButtonComponent.cs new file mode 100644 index 000000000..4b9fa2753 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ButtonComponent.cs @@ -0,0 +1,61 @@ +namespace Discord +{ + /// + /// Represents a Button. + /// + public class ButtonComponent : IMessageComponent + { + /// + public ComponentType Type => ComponentType.Button; + + /// + /// Gets the of this button, example buttons with each style can be found Here. + /// + public ButtonStyle Style { get; } + + /// + /// Gets the label of the button, this is the text that is shown. + /// + public string Label { get; } + + /// + /// Gets the displayed with this button. + /// + public IEmote Emote { get; } + + /// + public string CustomId { get; } + + /// + /// Gets the URL for a button. + /// + /// + /// You cannot have a button with a URL and a CustomId. + /// + public string Url { get; } + + /// + /// Gets whether this button is disabled or not. + /// + public bool IsDisabled { get; } + + /// + /// Turns this button into a button builder. + /// + /// + /// A newly created button builder with the same properties as this button. + /// + public ButtonBuilder ToBuilder() + => new ButtonBuilder(Label, CustomId, Style, Url, Emote, IsDisabled); + + internal ButtonComponent(ButtonStyle style, string label, IEmote emote, string customId, string url, bool isDisabled) + { + Style = style; + Label = label; + Emote = emote; + CustomId = customId; + Url = url; + IsDisabled = isDisabled; + } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ButtonStyle.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ButtonStyle.cs new file mode 100644 index 000000000..92d48ab4f --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ButtonStyle.cs @@ -0,0 +1,33 @@ +namespace Discord +{ + /// + /// Represents different styles to use with buttons. You can see an example of the different styles at + /// + public enum ButtonStyle + { + /// + /// A Blurple button + /// + Primary = 1, + + /// + /// A Grey (or gray) button + /// + Secondary = 2, + + /// + /// A Green button + /// + Success = 3, + + /// + /// A Red button + /// + Danger = 4, + + /// + /// A button with a little popup box indicating that this button is a link. + /// + Link = 5 + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ComponentBuilder.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ComponentBuilder.cs new file mode 100644 index 000000000..4461a4205 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ComponentBuilder.cs @@ -0,0 +1,1064 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Discord.Utils; + +namespace Discord +{ + /// + /// Represents a builder for creating a . + /// + public class ComponentBuilder + { + /// + /// The max length of a . + /// + public const int MaxCustomIdLength = 100; + + /// + /// The max amount of rows a message can have. + /// + public const int MaxActionRowCount = 5; + + /// + /// Gets or sets the Action Rows for this Component Builder. + /// + /// cannot be null. + /// count exceeds . + public List ActionRows + { + get => _actionRows; + set + { + if (value == null) + throw new ArgumentNullException(nameof(value), $"{nameof(ActionRows)} cannot be null."); + if (value.Count > MaxActionRowCount) + throw new ArgumentOutOfRangeException(nameof(value), $"Action row count must be less than or equal to {MaxActionRowCount}."); + _actionRows = value; + } + } + + private List _actionRows; + + /// + /// Creates a new builder from a message. + /// + /// The message to create the builder from. + /// The newly created builder. + public static ComponentBuilder FromMessage(IMessage message) + => FromComponents(message.Components); + + /// + /// Creates a new builder from the provided list of components. + /// + /// The components to create the builder from. + /// The newly created builder. + public static ComponentBuilder FromComponents(IReadOnlyCollection components) + { + var builder = new ComponentBuilder(); + for (int i = 0; i != components.Count; i++) + { + var component = components.ElementAt(i); + builder.AddComponent(component, i); + } + return builder; + } + + internal void AddComponent(IMessageComponent component, int row) + { + switch (component) + { + case ButtonComponent button: + WithButton(button.Label, button.CustomId, button.Style, button.Emote, button.Url, button.IsDisabled, row); + break; + case ActionRowComponent actionRow: + foreach (var cmp in actionRow.Components) + AddComponent(cmp, row); + break; + case SelectMenuComponent menu: + WithSelectMenu(menu.CustomId, menu.Options.Select(x => new SelectMenuOptionBuilder(x.Label, x.Value, x.Description, x.Emote, x.IsDefault)).ToList(), menu.Placeholder, menu.MinValues, menu.MaxValues, menu.IsDisabled, row); + break; + } + } + + /// + /// Adds a to the at the specific row. + /// If the row cannot accept the component then it will add it to a row that can. + /// + /// The custom id of the menu. + /// The options of the menu. + /// The placeholder of the menu. + /// The min values of the placeholder. + /// The max values of the placeholder. + /// Whether or not the menu is disabled. + /// The row to add the menu to. + /// + public ComponentBuilder WithSelectMenu(string customId, List options, + string placeholder = null, int minValues = 1, int maxValues = 1, bool disabled = false, int row = 0) + { + return WithSelectMenu(new SelectMenuBuilder() + .WithCustomId(customId) + .WithOptions(options) + .WithPlaceholder(placeholder) + .WithMaxValues(maxValues) + .WithMinValues(minValues) + .WithDisabled(disabled), + row); + } + + /// + /// Adds a to the at the specific row. + /// If the row cannot accept the component then it will add it to a row that can. + /// + /// The menu to add. + /// The row to attempt to add this component on. + /// There is no more row to add a menu. + /// must be less than . + /// The current builder. + public ComponentBuilder WithSelectMenu(SelectMenuBuilder menu, int row = 0) + { + Preconditions.LessThan(row, MaxActionRowCount, nameof(row)); + if (menu.Options.Distinct().Count() != menu.Options.Count) + throw new InvalidOperationException("Please make sure that there is no duplicates values."); + + var builtMenu = menu.Build(); + + if (_actionRows == null) + { + _actionRows = new List + { + new ActionRowBuilder().AddComponent(builtMenu) + }; + } + else + { + if (_actionRows.Count == row) + _actionRows.Add(new ActionRowBuilder().AddComponent(builtMenu)); + else + { + ActionRowBuilder actionRow; + if (_actionRows.Count > row) + actionRow = _actionRows.ElementAt(row); + else + { + actionRow = new ActionRowBuilder(); + _actionRows.Add(actionRow); + } + + if (actionRow.CanTakeComponent(builtMenu)) + actionRow.AddComponent(builtMenu); + else if (row < MaxActionRowCount) + WithSelectMenu(menu, row + 1); + else + throw new InvalidOperationException($"There is no more row to add a {nameof(builtMenu)}"); + } + } + + return this; + } + + /// + /// Adds a with specified parameters to the at the specific row. + /// If the row cannot accept the component then it will add it to a row that can. + /// + /// The label text for the newly added button. + /// The style of this newly added button. + /// A to be used with this button. + /// The custom id of the newly added button. + /// A URL to be used only if the is a Link. + /// Whether or not the newly created button is disabled. + /// The row the button should be placed on. + /// The current builder. + public ComponentBuilder WithButton( + string label = null, + string customId = null, + ButtonStyle style = ButtonStyle.Primary, + IEmote emote = null, + string url = null, + bool disabled = false, + int row = 0) + { + var button = new ButtonBuilder() + .WithLabel(label) + .WithStyle(style) + .WithEmote(emote) + .WithCustomId(customId) + .WithUrl(url) + .WithDisabled(disabled); + + return WithButton(button, row); + } + + /// + /// Adds a to the at the specific row. + /// If the row cannot accept the component then it will add it to a row that can. + /// + /// The button to add. + /// The row to add the button. + /// There is no more row to add a menu. + /// must be less than . + /// The current builder. + public ComponentBuilder WithButton(ButtonBuilder button, int row = 0) + { + Preconditions.LessThan(row, MaxActionRowCount, nameof(row)); + + var builtButton = button.Build(); + + if (_actionRows == null) + { + _actionRows = new List + { + new ActionRowBuilder().AddComponent(builtButton) + }; + } + else + { + if (_actionRows.Count == row) + _actionRows.Add(new ActionRowBuilder().AddComponent(builtButton)); + else + { + ActionRowBuilder actionRow; + if (_actionRows.Count > row) + actionRow = _actionRows.ElementAt(row); + else + { + actionRow = new ActionRowBuilder(); + _actionRows.Add(actionRow); + } + + if (actionRow.CanTakeComponent(builtButton)) + actionRow.AddComponent(builtButton); + else if (row < MaxActionRowCount) + WithButton(button, row + 1); + else + throw new InvalidOperationException($"There is no more row to add a {nameof(button)}"); + } + } + + return this; + } + + /// + /// Builds this builder into a used to send your components. + /// + /// A that can be sent with . + public MessageComponent Build() + { + return _actionRows != null + ? new MessageComponent(_actionRows.Select(x => x.Build()).ToList()) + : MessageComponent.Empty; + } + } + + /// + /// Represents a class used to build Action rows. + /// + public class ActionRowBuilder + { + /// + /// The max amount of child components this row can hold. + /// + public const int MaxChildCount = 5; + + /// + /// Gets or sets the components inside this row. + /// + /// cannot be null. + /// count exceeds . + public List Components + { + get => _components; + set + { + if (value == null) + throw new ArgumentNullException(nameof(value), $"{nameof(Components)} cannot be null."); + + _components = value.Count switch + { + 0 => throw new ArgumentOutOfRangeException(nameof(value), "There must be at least 1 component in a row."), + > MaxChildCount => throw new ArgumentOutOfRangeException(nameof(value), $"Action row can only contain {MaxChildCount} child components!"), + _ => value + }; + } + } + + private List _components = new List(); + + /// + /// Adds a list of components to the current row. + /// + /// The list of components to add. + /// + /// The current builder. + public ActionRowBuilder WithComponents(List components) + { + Components = components; + return this; + } + + /// + /// Adds a component at the end of the current row. + /// + /// The component to add. + /// Components count reached + /// The current builder. + public ActionRowBuilder AddComponent(IMessageComponent component) + { + if (Components.Count >= MaxChildCount) + throw new InvalidOperationException($"Components count reached {MaxChildCount}"); + + Components.Add(component); + return this; + } + + /// + /// Builds the current builder to a that can be used within a + /// + /// A that can be used within a + public ActionRowComponent Build() + { + return new ActionRowComponent(_components); + } + + internal bool CanTakeComponent(IMessageComponent component) + { + switch (component.Type) + { + case ComponentType.ActionRow: + return false; + case ComponentType.Button: + if (Components.Any(x => x.Type == ComponentType.SelectMenu)) + return false; + else + return Components.Count < 5; + case ComponentType.SelectMenu: + return Components.Count == 0; + default: + return false; + } + } + } + + /// + /// Represents a class used to build 's. + /// + public class ButtonBuilder + { + /// + /// The max length of a . + /// + public const int MaxButtonLabelLength = 80; + + /// + /// Gets or sets the label of the current button. + /// + /// length exceeds . + /// length exceeds . + public string Label + { + get => _label; + set => _label = value?.Length switch + { + > MaxButtonLabelLength => throw new ArgumentOutOfRangeException(nameof(value), $"Label length must be less or equal to {MaxButtonLabelLength}."), + 0 => throw new ArgumentOutOfRangeException(nameof(value), "Label length must be at least 1."), + _ => value + }; + } + + /// + /// Gets or sets the custom id of the current button. + /// + /// length exceeds + /// length subceeds 1. + public string CustomId + { + get => _customId; + set => _customId = value?.Length switch + { + > ComponentBuilder.MaxCustomIdLength => throw new ArgumentOutOfRangeException(nameof(value), $"Custom Id length must be less or equal to {ComponentBuilder.MaxCustomIdLength}."), + 0 => throw new ArgumentOutOfRangeException(nameof(value), "Custom Id length must be at least 1."), + _ => value + }; + } + + /// + /// Gets or sets the of the current button. + /// + public ButtonStyle Style { get; set; } + + /// + /// Gets or sets the of the current button. + /// + public IEmote Emote { get; set; } + + /// + /// Gets or sets the url of the current button. + /// + public string Url { get; set; } + + /// + /// Gets or sets whether the current button is disabled. + /// + public bool IsDisabled { get; set; } + + private string _label; + private string _customId; + + /// + /// Creates a new instance of a . + /// + public ButtonBuilder() { } + + /// + /// Creates a new instance of a . + /// + /// The label to use on the newly created link button. + /// The url of this button. + /// The custom ID of this button. + /// The custom ID of this button. + /// The emote of this button. + /// Disabled this button or not. + public ButtonBuilder(string label = null, string customId = null, ButtonStyle style = ButtonStyle.Primary, string url = null, IEmote emote = null, bool isDisabled = false) + { + CustomId = customId; + Style = style; + Url = url; + Label = label; + IsDisabled = isDisabled; + Emote = emote; + } + + /// + /// Creates a new instance of a from instance of a . + /// + public ButtonBuilder(ButtonComponent button) + { + CustomId = button.CustomId; + Style = button.Style; + Url = button.Url; + Label = button.Label; + IsDisabled = button.IsDisabled; + Emote = button.Emote; + } + + /// + /// Creates a button with the style. + /// + /// The label for this link button. + /// The url for this link button to go to. + /// The emote for this link button. + /// A builder with the newly created button. + public static ButtonBuilder CreateLinkButton(string label, string url, IEmote emote = null) + => new ButtonBuilder(label, null, ButtonStyle.Link, url, emote: emote); + + /// + /// Creates a button with the style. + /// + /// The label for this danger button. + /// The custom id for this danger button. + /// The emote for this danger button. + /// A builder with the newly created button. + public static ButtonBuilder CreateDangerButton(string label, string customId, IEmote emote = null) + => new ButtonBuilder(label, customId, ButtonStyle.Danger, emote: emote); + + /// + /// Creates a button with the style. + /// + /// The label for this primary button. + /// The custom id for this primary button. + /// The emote for this primary button. + /// A builder with the newly created button. + public static ButtonBuilder CreatePrimaryButton(string label, string customId, IEmote emote = null) + => new ButtonBuilder(label, customId, emote: emote); + + /// + /// Creates a button with the style. + /// + /// The label for this secondary button. + /// The custom id for this secondary button. + /// The emote for this secondary button. + /// A builder with the newly created button. + public static ButtonBuilder CreateSecondaryButton(string label, string customId, IEmote emote = null) + => new ButtonBuilder(label, customId, ButtonStyle.Secondary, emote: emote); + + /// + /// Creates a button with the style. + /// + /// The label for this success button. + /// The custom id for this success button. + /// The emote for this success button. + /// A builder with the newly created button. + public static ButtonBuilder CreateSuccessButton(string label, string customId, IEmote emote = null) + => new ButtonBuilder(label, customId, ButtonStyle.Success, emote: emote); + + /// + /// Sets the current buttons label to the specified text. + /// + /// The text for the label. + /// + /// The current builder. + public ButtonBuilder WithLabel(string label) + { + Label = label; + return this; + } + + /// + /// Sets the current buttons style. + /// + /// The style for this builders button. + /// The current builder. + public ButtonBuilder WithStyle(ButtonStyle style) + { + Style = style; + return this; + } + + /// + /// Sets the current buttons emote. + /// + /// The emote to use for the current button. + /// The current builder. + public ButtonBuilder WithEmote(IEmote emote) + { + Emote = emote; + return this; + } + + /// + /// Sets the current buttons url. + /// + /// The url to use for the current button. + /// The current builder. + public ButtonBuilder WithUrl(string url) + { + Url = url; + return this; + } + + /// + /// Sets the custom id of the current button. + /// + /// The id to use for the current button. + /// + /// The current builder. + public ButtonBuilder WithCustomId(string id) + { + CustomId = id; + return this; + } + + /// + /// Sets whether the current button is disabled. + /// + /// Whether the current button is disabled or not. + /// The current builder. + public ButtonBuilder WithDisabled(bool isDisabled) + { + IsDisabled = isDisabled; + return this; + } + + /// + /// Builds this builder into a to be used in a . + /// + /// A to be used in a . + /// A button must contain either a or a , but not both. + /// A button must have an or a . + /// A link button must contain a URL. + /// A URL must include a protocol (http or https). + /// A non-link button must contain a custom id + public ButtonComponent Build() + { + if (string.IsNullOrEmpty(Label) && Emote == null) + throw new InvalidOperationException("A button must have an Emote or a label!"); + + if (!(string.IsNullOrEmpty(Url) ^ string.IsNullOrEmpty(CustomId))) + throw new InvalidOperationException("A button must contain either a URL or a CustomId, but not both!"); + + if (Style == ButtonStyle.Link) + { + if (string.IsNullOrEmpty(Url)) + throw new InvalidOperationException("Link buttons must have a link associated with them"); + UrlValidation.ValidateButton(Url); + } + else if (string.IsNullOrEmpty(CustomId)) + throw new InvalidOperationException("Non-link buttons must have a custom id associated with them"); + + return new ButtonComponent(Style, Label, Emote, CustomId, Url, IsDisabled); + } + } + + /// + /// Represents a class used to build 's. + /// + public class SelectMenuBuilder + { + /// + /// The max length of a . + /// + public const int MaxPlaceholderLength = 100; + + /// + /// The maximum number of values for the and properties. + /// + public const int MaxValuesCount = 25; + + /// + /// The maximum number of options a can have. + /// + public const int MaxOptionCount = 25; + + /// + /// Gets or sets the custom id of the current select menu. + /// + /// length exceeds + /// length subceeds 1. + public string CustomId + { + get => _customId; + set => _customId = value?.Length switch + { + > ComponentBuilder.MaxCustomIdLength => throw new ArgumentOutOfRangeException(nameof(value), $"Custom Id length must be less or equal to {ComponentBuilder.MaxCustomIdLength}."), + 0 => throw new ArgumentOutOfRangeException(nameof(value), "Custom Id length must be at least 1."), + _ => value + }; + } + + /// + /// Gets or sets the placeholder text of the current select menu. + /// + /// length exceeds . + /// length subceeds 1. + public string Placeholder + { + get => _placeholder; + set => _placeholder = value?.Length switch + { + > MaxPlaceholderLength => throw new ArgumentOutOfRangeException(nameof(value), $"Placeholder length must be less or equal to {MaxPlaceholderLength}."), + 0 => throw new ArgumentOutOfRangeException(nameof(value), "Placeholder length must be at least 1."), + _ => value + }; + } + + /// + /// Gets or sets the minimum values of the current select menu. + /// + /// exceeds . + public int MinValues + { + get => _minValues; + set + { + Preconditions.AtMost(value, MaxValuesCount, nameof(MinValues)); + _minValues = value; + } + } + + /// + /// Gets or sets the maximum values of the current select menu. + /// + /// exceeds . + public int MaxValues + { + get => _maxValues; + set + { + Preconditions.AtMost(value, MaxValuesCount, nameof(MaxValues)); + _maxValues = value; + } + } + + /// + /// Gets or sets a collection of for this current select menu. + /// + /// count exceeds . + /// is null. + public List Options + { + get => _options; + set + { + if (value != null) + Preconditions.AtMost(value.Count, MaxOptionCount, nameof(Options)); + else + throw new ArgumentNullException(nameof(value), $"{nameof(Options)} cannot be null."); + + _options = value; + } + } + + /// + /// Gets or sets whether the current menu is disabled. + /// + public bool IsDisabled { get; set; } + + private List _options = new List(); + private int _minValues = 1; + private int _maxValues = 1; + private string _placeholder; + private string _customId; + + /// + /// Creates a new instance of a . + /// + public SelectMenuBuilder() { } + + /// + /// Creates a new instance of a from instance of . + /// + public SelectMenuBuilder(SelectMenuComponent selectMenu) + { + Placeholder = selectMenu.Placeholder; + CustomId = selectMenu.Placeholder; + MaxValues = selectMenu.MaxValues; + MinValues = selectMenu.MinValues; + IsDisabled = selectMenu.IsDisabled; + Options = selectMenu.Options? + .Select(x => new SelectMenuOptionBuilder(x.Label, x.Value, x.Description, x.Emote, x.IsDefault)) + .ToList(); + } + + /// + /// Creates a new instance of a . + /// + /// The custom id of this select menu. + /// The options for this select menu. + /// The placeholder of this select menu. + /// The max values of this select menu. + /// The min values of this select menu. + /// Disabled this select menu or not. + public SelectMenuBuilder(string customId, List options, string placeholder = null, int maxValues = 1, int minValues = 1, bool isDisabled = false) + { + CustomId = customId; + Options = options; + Placeholder = placeholder; + IsDisabled = isDisabled; + MaxValues = maxValues; + MinValues = minValues; + } + + /// + /// Sets the field CustomId. + /// + /// The value to set the field CustomId to. + /// + /// + /// The current builder. + /// + public SelectMenuBuilder WithCustomId(string customId) + { + CustomId = customId; + return this; + } + + /// + /// Sets the field placeholder. + /// + /// The value to set the field placeholder to. + /// + /// + /// The current builder. + /// + public SelectMenuBuilder WithPlaceholder(string placeholder) + { + Placeholder = placeholder; + return this; + } + + /// + /// Sets the field minValues. + /// + /// The value to set the field minValues to. + /// + /// + /// The current builder. + /// + public SelectMenuBuilder WithMinValues(int minValues) + { + MinValues = minValues; + return this; + } + + /// + /// Sets the field maxValues. + /// + /// The value to set the field maxValues to. + /// + /// + /// The current builder. + /// + public SelectMenuBuilder WithMaxValues(int maxValues) + { + MaxValues = maxValues; + return this; + } + + /// + /// Sets the field options. + /// + /// The value to set the field options to. + /// + /// + /// The current builder. + /// + public SelectMenuBuilder WithOptions(List options) + { + Options = options; + return this; + } + + /// + /// Add one option to menu options. + /// + /// The option builder class containing the option properties. + /// Options count reached . + /// + /// The current builder. + /// + public SelectMenuBuilder AddOption(SelectMenuOptionBuilder option) + { + if (Options.Count >= MaxOptionCount) + throw new InvalidOperationException($"Options count reached {MaxOptionCount}."); + + Options.Add(option); + return this; + } + + /// + /// Add one option to menu options. + /// + /// The label for this option. + /// The value of this option. + /// The description of this option. + /// The emote of this option. + /// Render this option as selected by default or not. + /// Options count reached . + /// + /// The current builder. + /// + public SelectMenuBuilder AddOption(string label, string value, string description = null, IEmote emote = null, bool? isDefault = null) + { + AddOption(new SelectMenuOptionBuilder(label, value, description, emote, isDefault)); + return this; + } + + /// + /// Sets whether the current menu is disabled. + /// + /// Whether the current menu is disabled or not. + /// + /// The current builder. + /// + public SelectMenuBuilder WithDisabled(bool isDisabled) + { + IsDisabled = isDisabled; + return this; + } + + /// + /// Builds a + /// + /// The newly built + public SelectMenuComponent Build() + { + var options = Options?.Select(x => x.Build()).ToList(); + + return new SelectMenuComponent(CustomId, options, Placeholder, MinValues, MaxValues, IsDisabled); + } + } + + /// + /// Represents a class used to build 's. + /// + public class SelectMenuOptionBuilder + { + /// + /// The maximum length of a . + /// + public const int MaxSelectLabelLength = 100; + + /// + /// The maximum length of a . + /// + public const int MaxDescriptionLength = 100; + + /// + /// The maximum length of a . + /// + public const int MaxSelectValueLength = 100; + + /// + /// Gets or sets the label of the current select menu. + /// + /// length exceeds + /// length subceeds 1. + public string Label + { + get => _label; + set => _label = value?.Length switch + { + > MaxSelectLabelLength => throw new ArgumentOutOfRangeException(nameof(value), $"Label length must be less or equal to {MaxSelectLabelLength}."), + 0 => throw new ArgumentOutOfRangeException(nameof(value), "Label length must be at least 1."), + _ => value + }; + } + + /// + /// Gets or sets the value of the current select menu. + /// + /// length exceeds . + /// length subceeds 1. + public string Value + { + get => _value; + set => _value = value?.Length switch + { + > MaxSelectValueLength => throw new ArgumentOutOfRangeException(nameof(value), $"Value length must be less or equal to {MaxSelectValueLength}."), + 0 => throw new ArgumentOutOfRangeException(nameof(value), "Value length must be at least 1."), + _ => value + }; + } + + /// + /// Gets or sets this menu options description. + /// + /// length exceeds . + /// length subceeds 1. + public string Description + { + get => _description; + set => _description = value?.Length switch + { + > MaxDescriptionLength => throw new ArgumentOutOfRangeException(nameof(value), $"Description length must be less or equal to {MaxDescriptionLength}."), + 0 => throw new ArgumentOutOfRangeException(nameof(value), "Description length must be at least 1."), + _ => value + }; + } + + /// + /// Gets or sets the emote of this option. + /// + public IEmote Emote { get; set; } + + /// + /// Gets or sets the whether or not this option will render selected by default. + /// + public bool? IsDefault { get; set; } + + private string _label; + private string _value; + private string _description; + + /// + /// Creates a new instance of a . + /// + public SelectMenuOptionBuilder() { } + + /// + /// Creates a new instance of a . + /// + /// The label for this option. + /// The value of this option. + /// The description of this option. + /// The emote of this option. + /// Render this option as selected by default or not. + public SelectMenuOptionBuilder(string label, string value, string description = null, IEmote emote = null, bool? isDefault = null) + { + Label = label; + Value = value; + Description = description; + Emote = emote; + IsDefault = isDefault; + } + + /// + /// Creates a new instance of a from instance of a . + /// + public SelectMenuOptionBuilder(SelectMenuOption option) + { + Label = option.Label; + Value = option.Value; + Description = option.Description; + Emote = option.Emote; + IsDefault = option.IsDefault; + } + + /// + /// Sets the field label. + /// + /// The value to set the field label to. + /// + /// + /// The current builder. + /// + public SelectMenuOptionBuilder WithLabel(string label) + { + Label = label; + return this; + } + + /// + /// Sets the field value. + /// + /// The value to set the field value to. + /// + /// + /// The current builder. + /// + public SelectMenuOptionBuilder WithValue(string value) + { + Value = value; + return this; + } + + /// + /// Sets the field description. + /// + /// The value to set the field description to. + /// + /// + /// The current builder. + /// + public SelectMenuOptionBuilder WithDescription(string description) + { + Description = description; + return this; + } + + /// + /// Sets the field emote. + /// + /// The value to set the field emote to. + /// + /// The current builder. + /// + public SelectMenuOptionBuilder WithEmote(IEmote emote) + { + Emote = emote; + return this; + } + + /// + /// Sets the field default. + /// + /// The value to set the field default to. + /// + /// The current builder. + /// + public SelectMenuOptionBuilder WithDefault(bool isDefault) + { + IsDefault = isDefault; + return this; + } + + /// + /// Builds a . + /// + /// The newly built . + public SelectMenuOption Build() + { + return new SelectMenuOption(Label, Value, Description, Emote, IsDefault); + } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ComponentType.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ComponentType.cs new file mode 100644 index 000000000..70bc1f301 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/ComponentType.cs @@ -0,0 +1,23 @@ +namespace Discord +{ + /// + /// Represents a type of a component. + /// + public enum ComponentType + { + /// + /// A container for other components. + /// + ActionRow = 1, + + /// + /// A clickable button. + /// + Button = 2, + + /// + /// A select menu for picking from choices. + /// + SelectMenu = 3 + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/IComponentInteraction.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/IComponentInteraction.cs new file mode 100644 index 000000000..2a46e8f18 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/IComponentInteraction.cs @@ -0,0 +1,18 @@ +namespace Discord +{ + /// + /// Represents an interaction type for Message Components. + /// + public interface IComponentInteraction : IDiscordInteraction + { + /// + /// Gets the data received with this interaction, contains the button that was clicked. + /// + new IComponentInteractionData Data { get; } + + /// + /// Gets the message that contained the trigger for this interaction. + /// + IUserMessage Message { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/IComponentInteractionData.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/IComponentInteractionData.cs new file mode 100644 index 000000000..99b9b6f6c --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/IComponentInteractionData.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace Discord +{ + /// + /// Represents the data sent with the . + /// + public interface IComponentInteractionData : IDiscordInteractionData + { + /// + /// Gets the components Custom Id that was clicked. + /// + string CustomId { get; } + + /// + /// Gets the type of the component clicked. + /// + ComponentType Type { get; } + + /// + /// Gets the value(s) of a interaction response. + /// + IReadOnlyCollection Values { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/IMessageComponent.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/IMessageComponent.cs new file mode 100644 index 000000000..9366a44d6 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/IMessageComponent.cs @@ -0,0 +1,18 @@ +namespace Discord +{ + /// + /// Represents a message component on a message. + /// + public interface IMessageComponent + { + /// + /// Gets the of this Message Component. + /// + ComponentType Type { get; } + + /// + /// Gets the custom id of the component if possible; otherwise . + /// + string CustomId { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/MessageComponent.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/MessageComponent.cs new file mode 100644 index 000000000..720588681 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/MessageComponent.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + +namespace Discord +{ + /// + /// Represents a component object used to send components with messages. + /// + public class MessageComponent + { + /// + /// Gets the components to be used in a message. + /// + public IReadOnlyCollection Components { get; } + + internal MessageComponent(List components) + { + Components = components; + } + + /// + /// Returns a empty . + /// + internal static MessageComponent Empty + => new MessageComponent(new List()); + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/SelectMenuComponent.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/SelectMenuComponent.cs new file mode 100644 index 000000000..229c1e148 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/SelectMenuComponent.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Discord +{ + /// + /// Represents a select menu component defined at + /// + public class SelectMenuComponent : IMessageComponent + { + /// + public ComponentType Type => ComponentType.SelectMenu; + + /// + public string CustomId { get; } + + /// + /// Gets the menus options to select from. + /// + public IReadOnlyCollection Options { get; } + + /// + /// Gets the custom placeholder text if nothing is selected. + /// + public string Placeholder { get; } + + /// + /// Gets the minimum number of items that must be chosen. + /// + public int MinValues { get; } + + /// + /// Gets the maximum number of items that can be chosen. + /// + public int MaxValues { get; } + + /// + /// Gets whether this menu is disabled or not. + /// + public bool IsDisabled { get; } + + /// + /// Turns this select menu into a builder. + /// + /// + /// A newly create builder with the same properties as this select menu. + /// + public SelectMenuBuilder ToBuilder() + => new SelectMenuBuilder( + CustomId, + Options.Select(x => new SelectMenuOptionBuilder(x.Label, x.Value, x.Description, x.Emote, x.IsDefault)).ToList(), + Placeholder, + MaxValues, + MinValues, + IsDisabled); + + internal SelectMenuComponent(string customId, List options, string placeholder, int minValues, int maxValues, bool disabled) + { + CustomId = customId; + Options = options; + Placeholder = placeholder; + MinValues = minValues; + MaxValues = maxValues; + IsDisabled = disabled; + } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/MessageComponents/SelectMenuOption.cs b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/SelectMenuOption.cs new file mode 100644 index 000000000..6856e1ee3 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/MessageComponents/SelectMenuOption.cs @@ -0,0 +1,42 @@ +namespace Discord +{ + /// + /// Represents a choice for a . + /// + public class SelectMenuOption + { + /// + /// Gets the user-facing name of the option. + /// + public string Label { get; } + + /// + /// Gets the dev-define value of the option. + /// + public string Value { get; } + + /// + /// Gets a description of the option. + /// + public string Description { get; } + + /// + /// Gets the displayed with this menu option. + /// + public IEmote Emote { get; } + + /// + /// Gets whether or not this option will render as selected by default. + /// + public bool? IsDefault { get; } + + internal SelectMenuOption(string label, string value, string description, IEmote emote, bool? defaultValue) + { + Label = label; + Value = value; + Description = description; + Emote = emote; + IsDefault = defaultValue; + } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/SlashCommands/IAutocompleteInteraction.cs b/src/Discord.Net.Core/Entities/Interactions/SlashCommands/IAutocompleteInteraction.cs new file mode 100644 index 000000000..bb5343d84 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/SlashCommands/IAutocompleteInteraction.cs @@ -0,0 +1,13 @@ +namespace Discord +{ + /// + /// Represents a . + /// + public interface IAutocompleteInteraction : IDiscordInteraction + { + /// + /// Gets the autocomplete data of this interaction. + /// + new IAutocompleteInteractionData Data { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/SlashCommands/IAutocompleteInteractionData.cs b/src/Discord.Net.Core/Entities/Interactions/SlashCommands/IAutocompleteInteractionData.cs new file mode 100644 index 000000000..e6d1e9fae --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/SlashCommands/IAutocompleteInteractionData.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; + +namespace Discord +{ + /// + /// Represents data for a slash commands autocomplete interaction. + /// + public interface IAutocompleteInteractionData : IDiscordInteractionData + { + /// + /// Gets the name of the invoked command. + /// + string CommandName { get; } + + /// + /// Gets the id of the invoked command. + /// + ulong CommandId { get; } + + /// + /// Gets the type of the invoked command. + /// + ApplicationCommandType Type { get; } + + /// + /// Gets the version of the invoked command. + /// + ulong Version { get; } + + /// + /// Gets the current autocomplete option that is actively being filled out. + /// + AutocompleteOption Current { get; } + + /// + /// Gets a collection of all the other options the executing users has filled out. + /// + IReadOnlyCollection Options { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/SlashCommands/ISlashCommandInteraction.cs b/src/Discord.Net.Core/Entities/Interactions/SlashCommands/ISlashCommandInteraction.cs new file mode 100644 index 000000000..556182987 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/SlashCommands/ISlashCommandInteraction.cs @@ -0,0 +1,13 @@ +namespace Discord +{ + /// + /// Represents a slash command interaction. + /// + public interface ISlashCommandInteraction : IDiscordInteraction + { + /// + /// Gets the data associated with this interaction. + /// + new IApplicationCommandInteractionData Data { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/SlashCommands/SlashCommandBuilder.cs b/src/Discord.Net.Core/Entities/Interactions/SlashCommands/SlashCommandBuilder.cs new file mode 100644 index 000000000..b4fc89cc2 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/SlashCommands/SlashCommandBuilder.cs @@ -0,0 +1,640 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +namespace Discord +{ + /// + /// Represents a class used to build slash commands. + /// + public class SlashCommandBuilder + { + /// + /// Returns the maximum length a commands name allowed by Discord + /// + public const int MaxNameLength = 32; + /// + /// Returns the maximum length of a commands description allowed by Discord. + /// + public const int MaxDescriptionLength = 100; + /// + /// Returns the maximum count of command options allowed by Discord + /// + public const int MaxOptionsCount = 25; + + /// + /// Gets or sets the name of this slash command. + /// + public string Name + { + get => _name; + set + { + Preconditions.NotNullOrEmpty(value, nameof(value)); + Preconditions.AtLeast(value.Length, 1, nameof(value)); + Preconditions.AtMost(value.Length, MaxNameLength, nameof(value)); + + // Discord updated the docs, this regex prevents special characters like @!$%(... etc, + // https://discord.com/developers/docs/interactions/slash-commands#applicationcommand + if (!Regex.IsMatch(value, @"^[\w-]{1,32}$")) + throw new ArgumentException("Command name cannot contain any special characters or whitespaces!", nameof(value)); + + _name = value; + } + } + + /// + /// Gets or sets a 1-100 length description of this slash command + /// + public string Description + { + get => _description; + set + { + Preconditions.NotNullOrEmpty(value, nameof(Description)); + Preconditions.AtLeast(value.Length, 1, nameof(Description)); + Preconditions.AtMost(value.Length, MaxDescriptionLength, nameof(Description)); + + _description = value; + } + } + + /// + /// Gets or sets the options for this command. + /// + public List Options + { + get => _options; + set + { + Preconditions.AtMost(value?.Count ?? 0, MaxOptionsCount, nameof(value)); + _options = value; + } + } + + /// + /// Gets or sets whether the command is enabled by default when the app is added to a guild + /// + public bool IsDefaultPermission { get; set; } = true; + + private string _name; + private string _description; + private List _options; + + /// + /// Build the current builder into a class. + /// + /// A that can be used to create slash commands. + public SlashCommandProperties Build() + { + var props = new SlashCommandProperties + { + Name = Name, + Description = Description, + IsDefaultPermission = IsDefaultPermission, + }; + + if (Options != null && Options.Any()) + { + var options = new List(); + + Options.OrderByDescending(x => x.IsRequired ?? false).ToList().ForEach(x => options.Add(x.Build())); + + props.Options = options; + } + + return props; + } + + /// + /// Sets the field name. + /// + /// The value to set the field name to. + /// + /// The current builder. + /// + public SlashCommandBuilder WithName(string name) + { + Name = name; + return this; + } + + /// + /// Sets the description of the current command. + /// + /// The description of this command. + /// The current builder. + public SlashCommandBuilder WithDescription(string description) + { + Description = description; + return this; + } + + /// + /// Sets the default permission of the current command. + /// + /// The default permission value to set. + /// The current builder. + public SlashCommandBuilder WithDefaultPermission(bool value) + { + IsDefaultPermission = value; + return this; + } + + /// + /// Adds an option to the current slash command. + /// + /// The name of the option to add. + /// The type of this option. + /// The description of this option. + /// If this option is required for this command. + /// If this option is the default option. + /// If this option is set to autocomplete. + /// The options of the option to add. + /// The allowed channel types for this option. + /// The choices of this option. + /// The smallest number value the user can input. + /// The largest number value the user can input. + /// The current builder. + public SlashCommandBuilder AddOption(string name, ApplicationCommandOptionType type, + string description, bool? isRequired = null, bool? isDefault = null, bool isAutocomplete = false, double? minValue = null, double? maxValue = null, + List options = null, List channelTypes = null, params ApplicationCommandOptionChoiceProperties[] choices) + { + // Make sure the name matches the requirements from discord + Preconditions.NotNullOrEmpty(name, nameof(name)); + Preconditions.AtLeast(name.Length, 1, nameof(name)); + Preconditions.AtMost(name.Length, MaxNameLength, nameof(name)); + + // Discord updated the docs, this regex prevents special characters like @!$%( and s p a c e s.. etc, + // https://discord.com/developers/docs/interactions/slash-commands#applicationcommand + if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) + throw new ArgumentException("Command name cannot contain any special characters or whitespaces!", nameof(name)); + + // same with description + Preconditions.NotNullOrEmpty(description, nameof(description)); + Preconditions.AtLeast(description.Length, 1, nameof(description)); + Preconditions.AtMost(description.Length, MaxDescriptionLength, nameof(description)); + + // make sure theres only one option with default set to true + if (isDefault == true && Options?.Any(x => x.IsDefault == true) == true) + throw new ArgumentException("There can only be one command option with default set to true!", nameof(isDefault)); + + var option = new SlashCommandOptionBuilder + { + Name = name, + Description = description, + IsRequired = isRequired, + IsDefault = isDefault, + Options = options, + Type = type, + IsAutocomplete = isAutocomplete, + Choices = (choices ?? Array.Empty()).ToList(), + ChannelTypes = channelTypes, + MinValue = minValue, + MaxValue = maxValue, + }; + + return AddOption(option); + } + + /// + /// Adds an option to this slash command. + /// + /// The option to add. + /// The current builder. + public SlashCommandBuilder AddOption(SlashCommandOptionBuilder option) + { + Options ??= new List(); + + if (Options.Count >= MaxOptionsCount) + throw new InvalidOperationException($"Cannot have more than {MaxOptionsCount} options!"); + + Preconditions.NotNull(option, nameof(option)); + + Options.Add(option); + return this; + } + /// + /// Adds a collection of options to the current slash command. + /// + /// The collection of options to add. + /// The current builder. + public SlashCommandBuilder AddOptions(params SlashCommandOptionBuilder[] options) + { + if (options == null) + throw new ArgumentNullException(nameof(options), "Options cannot be null!"); + + if (options.Length == 0) + throw new ArgumentException("Options cannot be empty!", nameof(options)); + + Options ??= new List(); + + if (Options.Count + options.Length > MaxOptionsCount) + throw new ArgumentOutOfRangeException(nameof(options), $"Cannot have more than {MaxOptionsCount} options!"); + + Options.AddRange(options); + return this; + } + } + + /// + /// Represents a class used to build options for the . + /// + public class SlashCommandOptionBuilder + { + /// + /// The max length of a choice's name allowed by Discord. + /// + public const int ChoiceNameMaxLength = 100; + + /// + /// The maximum number of choices allowed by Discord. + /// + public const int MaxChoiceCount = 25; + + private string _name; + private string _description; + + /// + /// Gets or sets the name of this option. + /// + public string Name + { + get => _name; + set + { + if (value != null) + { + Preconditions.AtLeast(value.Length, 1, nameof(value)); + Preconditions.AtMost(value.Length, SlashCommandBuilder.MaxNameLength, nameof(value)); + if (!Regex.IsMatch(value, @"^[\w-]{1,32}$")) + throw new ArgumentException("Option name cannot contain any special characters or whitespaces!", nameof(value)); + } + + _name = value; + } + } + + /// + /// Gets or sets the description of this option. + /// + public string Description + { + get => _description; + set + { + if (value != null) + { + Preconditions.AtLeast(value.Length, 1, nameof(value)); + Preconditions.AtMost(value.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(value)); + } + + _description = value; + } + } + + /// + /// Gets or sets the type of this option. + /// + public ApplicationCommandOptionType Type { get; set; } + + /// + /// Gets or sets whether or not this options is the first required option for the user to complete. only one option can be default. + /// + public bool? IsDefault { get; set; } + + /// + /// Gets or sets if the option is required. + /// + public bool? IsRequired { get; set; } = null; + + /// + /// Gets or sets whether or not this option supports autocomplete. + /// + public bool IsAutocomplete { get; set; } + + /// + /// Gets or sets the smallest number value the user can input. + /// + public double? MinValue { get; set; } + + /// + /// Gets or sets the largest number value the user can input. + /// + public double? MaxValue { get; set; } + + /// + /// Gets or sets the choices for string and int types for the user to pick from. + /// + public List Choices { get; set; } + + /// + /// Gets or sets if this option is a subcommand or subcommand group type, these nested options will be the parameters. + /// + public List Options { get; set; } + + /// + /// Gets or sets the allowed channel types for this option. + /// + public List ChannelTypes { get; set; } + + /// + /// Builds the current option. + /// + /// The built version of this option. + public ApplicationCommandOptionProperties Build() + { + bool isSubType = Type == ApplicationCommandOptionType.SubCommandGroup; + bool isIntType = Type == ApplicationCommandOptionType.Integer; + + if (isSubType && (Options == null || !Options.Any())) + throw new InvalidOperationException("SubCommands/SubCommandGroups must have at least one option"); + + if (!isSubType && Options != null && Options.Any() && Type != ApplicationCommandOptionType.SubCommand) + throw new InvalidOperationException($"Cannot have options on {Type} type"); + + if (isIntType && MinValue != null && MinValue % 1 != 0) + throw new InvalidOperationException("MinValue cannot have decimals on Integer command options."); + + if (isIntType && MaxValue != null && MaxValue % 1 != 0) + throw new InvalidOperationException("MaxValue cannot have decimals on Integer command options."); + + return new ApplicationCommandOptionProperties + { + Name = Name, + Description = Description, + IsDefault = IsDefault, + IsRequired = IsRequired, + Type = Type, + Options = Options?.Count > 0 + ? Options.OrderByDescending(x => x.IsRequired ?? false).Select(x => x.Build()).ToList() + : new List(), + Choices = Choices, + IsAutocomplete = IsAutocomplete, + ChannelTypes = ChannelTypes, + MinValue = MinValue, + MaxValue = MaxValue + }; + } + + /// + /// Adds an option to the current slash command. + /// + /// The name of the option to add. + /// The type of this option. + /// The description of this option. + /// If this option is required for this command. + /// If this option is the default option. + /// If this option supports autocomplete. + /// The options of the option to add. + /// The allowed channel types for this option. + /// The choices of this option. + /// The smallest number value the user can input. + /// The largest number value the user can input. + /// The current builder. + public SlashCommandOptionBuilder AddOption(string name, ApplicationCommandOptionType type, + string description, bool? required = null, bool isDefault = false, bool isAutocomplete = false, double? minValue = null, double? maxValue = null, + List options = null, List channelTypes = null, params ApplicationCommandOptionChoiceProperties[] choices) + { + // Make sure the name matches the requirements from discord + Preconditions.NotNullOrEmpty(name, nameof(name)); + Preconditions.AtLeast(name.Length, 1, nameof(name)); + Preconditions.AtMost(name.Length, SlashCommandBuilder.MaxNameLength, nameof(name)); + + // Discord updated the docs, this regex prevents special characters like @!$%( and s p a c e s.. etc, + // https://discord.com/developers/docs/interactions/slash-commands#applicationcommand + if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) + throw new ArgumentException("Command name cannot contain any special characters or whitespaces!", nameof(name)); + + // same with description + Preconditions.NotNullOrEmpty(description, nameof(description)); + Preconditions.AtLeast(description.Length, 1, nameof(description)); + Preconditions.AtMost(description.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(description)); + + // make sure theres only one option with default set to true + if (isDefault && Options?.Any(x => x.IsDefault == true) == true) + throw new ArgumentException("There can only be one command option with default set to true!", nameof(isDefault)); + + var option = new SlashCommandOptionBuilder + { + Name = name, + Description = description, + IsRequired = required, + IsDefault = isDefault, + IsAutocomplete = isAutocomplete, + MinValue = minValue, + MaxValue = maxValue, + Options = options, + Type = type, + Choices = (choices ?? Array.Empty()).ToList(), + ChannelTypes = channelTypes + }; + + return AddOption(option); + } + /// + /// Adds a sub option to the current option. + /// + /// The sub option to add. + /// The current builder. + public SlashCommandOptionBuilder AddOption(SlashCommandOptionBuilder option) + { + Options ??= new List(); + + if (Options.Count >= SlashCommandBuilder.MaxOptionsCount) + throw new InvalidOperationException($"There can only be {SlashCommandBuilder.MaxOptionsCount} options per sub command group!"); + + Preconditions.NotNull(option, nameof(option)); + + Options.Add(option); + return this; + } + + /// + /// Adds a choice to the current option. + /// + /// The name of the choice. + /// The value of the choice. + /// The current builder. + public SlashCommandOptionBuilder AddChoice(string name, int value) + { + return AddChoiceInternal(name, value); + } + + /// + /// Adds a choice to the current option. + /// + /// The name of the choice. + /// The value of the choice. + /// The current builder. + public SlashCommandOptionBuilder AddChoice(string name, string value) + { + return AddChoiceInternal(name, value); + } + + /// + /// Adds a choice to the current option. + /// + /// The name of the choice. + /// The value of the choice. + /// The current builder. + public SlashCommandOptionBuilder AddChoice(string name, double value) + { + return AddChoiceInternal(name, value); + } + + /// + /// Adds a choice to the current option. + /// + /// The name of the choice. + /// The value of the choice. + /// The current builder. + public SlashCommandOptionBuilder AddChoice(string name, float value) + { + return AddChoiceInternal(name, value); + } + + /// + /// Adds a choice to the current option. + /// + /// The name of the choice. + /// The value of the choice. + /// The current builder. + public SlashCommandOptionBuilder AddChoice(string name, long value) + { + return AddChoiceInternal(name, value); + } + + private SlashCommandOptionBuilder AddChoiceInternal(string name, object value) + { + Choices ??= new List(); + + if (Choices.Count >= MaxChoiceCount) + throw new InvalidOperationException($"Cannot add more than {MaxChoiceCount} choices!"); + + Preconditions.NotNull(name, nameof(name)); + Preconditions.NotNull(value, nameof(value)); + + Preconditions.AtLeast(name.Length, 1, nameof(name)); + Preconditions.AtMost(name.Length, 100, nameof(name)); + + if(value is string str) + { + Preconditions.AtLeast(str.Length, 1, nameof(value)); + Preconditions.AtMost(str.Length, 100, nameof(value)); + } + + Choices.Add(new ApplicationCommandOptionChoiceProperties + { + Name = name, + Value = value + }); + + return this; + } + + /// + /// Adds a channel type to the current option. + /// + /// The to add. + /// The current builder. + public SlashCommandOptionBuilder AddChannelType(ChannelType channelType) + { + ChannelTypes ??= new List(); + + ChannelTypes.Add(channelType); + + return this; + } + + /// + /// Sets the current builders name. + /// + /// The name to set the current option builder. + /// The current builder. + public SlashCommandOptionBuilder WithName(string name) + { + Name = name; + + return this; + } + + /// + /// Sets the current builders description. + /// + /// The description to set. + /// The current builder. + public SlashCommandOptionBuilder WithDescription(string description) + { + Description = description; + return this; + } + + /// + /// Sets the current builders required field. + /// + /// The value to set. + /// The current builder. + public SlashCommandOptionBuilder WithRequired(bool value) + { + IsRequired = value; + return this; + } + + /// + /// Sets the current builders default field. + /// + /// The value to set. + /// The current builder. + public SlashCommandOptionBuilder WithDefault(bool value) + { + IsDefault = value; + return this; + } + + /// + /// Sets the current builders autocomplete field. + /// + /// The value to set. + /// The current builder. + public SlashCommandOptionBuilder WithAutocomplete(bool value) + { + IsAutocomplete = value; + return this; + } + + /// + /// Sets the current builders min value field. + /// + /// The value to set. + /// The current builder. + public SlashCommandOptionBuilder WithMinValue(double value) + { + MinValue = value; + return this; + } + + /// + /// Sets the current builders max value field. + /// + /// The value to set. + /// The current builder. + public SlashCommandOptionBuilder WithMaxValue(double value) + { + MaxValue = value; + return this; + } + + /// + /// Sets the current type of this builder. + /// + /// The type to set. + /// The current builder. + public SlashCommandOptionBuilder WithType(ApplicationCommandOptionType type) + { + Type = type; + return this; + } + } +} diff --git a/src/Discord.Net.Core/Entities/Interactions/SlashCommands/SlashCommandProperties.cs b/src/Discord.Net.Core/Entities/Interactions/SlashCommands/SlashCommandProperties.cs new file mode 100644 index 000000000..20ba2868f --- /dev/null +++ b/src/Discord.Net.Core/Entities/Interactions/SlashCommands/SlashCommandProperties.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace Discord +{ + /// + /// Represents a class used to create slash commands. + /// + public class SlashCommandProperties : ApplicationCommandProperties + { + internal override ApplicationCommandType Type => ApplicationCommandType.Slash; + + /// + /// Gets or sets the discription of this command. + /// + public Optional Description { get; set; } + + /// + /// Gets or sets the options for this command. + /// + public Optional> Options { get; set; } + + internal SlashCommandProperties() { } + } +} diff --git a/src/Discord.Net.Core/Entities/Invites/TargetUserType.cs b/src/Discord.Net.Core/Entities/Invites/TargetUserType.cs index 74263b888..e1818d7a9 100644 --- a/src/Discord.Net.Core/Entities/Invites/TargetUserType.cs +++ b/src/Discord.Net.Core/Entities/Invites/TargetUserType.cs @@ -9,6 +9,10 @@ public enum TargetUserType /// /// The invite is for a Go Live stream. /// - Stream = 1 + Stream = 1, + /// + /// The invite is for embedded application. + /// + EmbeddedApplication = 2 } } diff --git a/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs b/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs index 89aaf5fde..0304120f5 100644 --- a/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs +++ b/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using Discord.Utils; namespace Discord { @@ -16,20 +17,20 @@ public class EmbedBuilder private EmbedThumbnail? _thumbnail; private List _fields; - /// - /// Returns the maximum number of fields allowed by Discord. + /// + /// Returns the maximum number of fields allowed by Discord. /// public const int MaxFieldCount = 25; - /// - /// Returns the maximum length of title allowed by Discord. + /// + /// Returns the maximum length of title allowed by Discord. /// public const int MaxTitleLength = 256; - /// - /// Returns the maximum length of description allowed by Discord. + /// + /// Returns the maximum length of description allowed by Discord. /// public const int MaxDescriptionLength = 4096; - /// - /// Returns the maximum length of total characters allowed by Discord. + /// + /// Returns the maximum length of total characters allowed by Discord. /// public const int MaxEmbedLength = 6000; @@ -88,9 +89,9 @@ public string ImageUrl } /// Gets or sets the list of of an . - /// An embed builder's fields collection is set to + /// An embed builder's fields collection is set to /// null. - /// Description length exceeds . + /// Fields count exceeds . /// /// The list of existing . public List Fields @@ -137,7 +138,7 @@ public List Fields /// Gets the total length of all embed properties. /// /// - /// The combined length of , , , + /// The combined length of , , , /// , , and . /// public int Length @@ -166,7 +167,7 @@ public EmbedBuilder WithTitle(string title) Title = title; return this; } - /// + /// /// Sets the description of an . /// /// The description to be set. @@ -178,7 +179,7 @@ public EmbedBuilder WithDescription(string description) Description = description; return this; } - /// + /// /// Sets the URL of an . /// /// The URL to be set. @@ -190,7 +191,7 @@ public EmbedBuilder WithUrl(string url) Url = url; return this; } - /// + /// /// Sets the thumbnail URL of an . /// /// The thumbnail URL to be set. @@ -401,11 +402,29 @@ public EmbedBuilder AddField(Action action) /// The built embed object. /// /// Total embed length exceeds . + /// Any Url must include its protocols (i.e http:// or https://). public Embed Build() { if (Length > MaxEmbedLength) throw new InvalidOperationException($"Total embed length must be less than or equal to {MaxEmbedLength}."); - + if (!string.IsNullOrEmpty(Url)) + UrlValidation.Validate(Url, true); + if (!string.IsNullOrEmpty(ThumbnailUrl)) + UrlValidation.Validate(ThumbnailUrl, true); + if (!string.IsNullOrEmpty(ImageUrl)) + UrlValidation.Validate(ImageUrl, true); + if (Author != null) + { + if (!string.IsNullOrEmpty(Author.Url)) + UrlValidation.Validate(Author.Url, true); + if (!string.IsNullOrEmpty(Author.IconUrl)) + UrlValidation.Validate(Author.IconUrl, true); + } + if(Footer != null) + { + if (!string.IsNullOrEmpty(Footer.IconUrl)) + UrlValidation.Validate(Footer.IconUrl, true); + } var fields = ImmutableArray.CreateBuilder(Fields.Count); for (int i = 0; i < Fields.Count; i++) fields.Add(Fields[i].Build()); diff --git a/src/Discord.Net.Core/Entities/Messages/FileAttachment.cs b/src/Discord.Net.Core/Entities/Messages/FileAttachment.cs new file mode 100644 index 000000000..dc5437861 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Messages/FileAttachment.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + public struct FileAttachment : IDisposable + { + public string FileName { get; set; } + public string Description { get; set; } + public bool IsSpoiler { get; set; } + +#pragma warning disable IDISP008 + public Stream Stream { get; } +#pragma warning restore IDISP008 + + private bool _isDisposed; + + /// + /// Creates a file attachment from a stream. + /// + /// The stream to create the attachment from. + /// The name of the attachment. + /// The description of the attachment. + public FileAttachment(Stream stream, string fileName, string description = null, bool isSpoiler = false) + { + _isDisposed = false; + FileName = fileName; + Description = description; + Stream = stream; + IsSpoiler = isSpoiler; + } + + /// + /// Create the file attachment from a file path. + /// + /// + /// This file path is NOT validated and is passed directly into a + /// . + /// + /// The path to the file. + /// + /// is a zero-length string, contains only white space, or contains one or more invalid + /// characters as defined by . + /// + /// is null. + /// + /// The specified path, file name, or both exceed the system-defined maximum length. For example, on + /// Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 + /// characters. + /// + /// is in an invalid format. + /// + /// The specified is invalid, (for example, it is on an unmapped drive). + /// + /// + /// specified a directory.-or- The caller does not have the required permission. + /// + /// The file specified in was not found. + /// + /// An I/O error occurred while opening the file. + public FileAttachment(string path, string description = null, bool isSpoiler = false) + { + _isDisposed = false; + Stream = File.OpenRead(path); + FileName = Path.GetFileName(path); + Description = description; + IsSpoiler = isSpoiler; + } + + public void Dispose() + { + if (!_isDisposed) + { + Stream?.Dispose(); + _isDisposed = true; + } + } + } +} diff --git a/src/Discord.Net.Core/Entities/Messages/IAttachment.cs b/src/Discord.Net.Core/Entities/Messages/IAttachment.cs index 655777998..e94e9f97c 100644 --- a/src/Discord.Net.Core/Entities/Messages/IAttachment.cs +++ b/src/Discord.Net.Core/Entities/Messages/IAttachment.cs @@ -55,5 +55,12 @@ public interface IAttachment /// The width of this attachment if it is a picture; otherwise null. /// int? Width { get; } + /// + /// Gets whether or not this attachment is ephemeral. + /// + /// + /// if the attachment is ephemeral; otherwise . + /// + bool Ephemeral { get; } } } diff --git a/src/Discord.Net.Core/Entities/Messages/IMessage.cs b/src/Discord.Net.Core/Entities/Messages/IMessage.cs index b5023eb59..f5f2ca007 100644 --- a/src/Discord.Net.Core/Entities/Messages/IMessage.cs +++ b/src/Discord.Net.Core/Entities/Messages/IMessage.cs @@ -53,6 +53,13 @@ public interface IMessage : ISnowflakeEntity, IDeletable /// string Content { get; } /// + /// Gets the clean content for this message. + /// + /// + /// A string that contains the body of the message stripped of mentions, markdown, emojis and pings; note that this field may be empty if there is an embed. + /// + string CleanContent { get; } + /// /// Gets the time this message was sent. /// /// @@ -165,12 +172,17 @@ public interface IMessage : ISnowflakeEntity, IDeletable IReadOnlyDictionary Reactions { get; } /// - /// Gets all stickers included in this message. + /// The 's attached to this message + /// + IReadOnlyCollection Components { get; } + + /// + /// Gets all stickers items included in this message. /// /// - /// A read-only collection of sticker objects. + /// A read-only collection of sticker item objects. /// - IReadOnlyCollection Stickers { get; } + IReadOnlyCollection Stickers { get; } /// /// Gets the flags related to this message. @@ -183,6 +195,14 @@ public interface IMessage : ISnowflakeEntity, IDeletable /// MessageFlags? Flags { get; } + /// + /// Gets the interaction this message is a response to. + /// + /// + /// A if the message is a response to an interaction; otherwise . + /// + IMessageInteraction Interaction { get; } + /// /// Adds a reaction to this message. /// diff --git a/src/Discord.Net.Core/Entities/Messages/IMessageInteraction.cs b/src/Discord.Net.Core/Entities/Messages/IMessageInteraction.cs new file mode 100644 index 000000000..ebd03b627 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Messages/IMessageInteraction.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents a partial within a message. + /// + public interface IMessageInteraction + { + /// + /// Gets the snowflake id of the interaction. + /// + ulong Id { get; } + + /// + /// Gets the type of the interaction. + /// + InteractionType Type { get; } + + /// + /// Gets the name of the application command used. + /// + string Name { get; } + + /// + /// Gets the who invoked the interaction. + /// + IUser User { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Messages/MessageFlags.cs b/src/Discord.Net.Core/Entities/Messages/MessageFlags.cs index 52d0f0e9e..6f9450372 100644 --- a/src/Discord.Net.Core/Entities/Messages/MessageFlags.cs +++ b/src/Discord.Net.Core/Entities/Messages/MessageFlags.cs @@ -32,5 +32,17 @@ public enum MessageFlags /// Flag given to messages that came from the urgent message system. /// Urgent = 1 << 4, + /// + /// Flag given to messages has an associated thread, with the same id as the message + /// + HasThread = 1 << 5, + /// + /// Flag given to messages that is only visible to the user who invoked the Interaction. + /// + Ephemeral = 1 << 6, + /// + /// Flag given to messages that is an Interaction Response and the bot is "thinking" + /// + Loading = 1 << 7 } } diff --git a/src/Discord.Net.Core/Entities/Messages/MessageInteraction.cs b/src/Discord.Net.Core/Entities/Messages/MessageInteraction.cs new file mode 100644 index 000000000..cbbebd932 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Messages/MessageInteraction.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents a partial within a message. + /// + /// The type of the user. + public class MessageInteraction : IMessageInteraction where TUser : IUser + { + /// + /// Gets the snowflake id of the interaction. + /// + public ulong Id { get; } + + /// + /// Gets the type of the interaction. + /// + public InteractionType Type { get; } + + /// + /// Gets the name of the application command used. + /// + public string Name { get; } + + /// + /// Gets the who invoked the interaction. + /// + public TUser User { get; } + + internal MessageInteraction(ulong id, InteractionType type, string name, TUser user) + { + Id = id; + Type = type; + Name = name; + User = user; + } + + IUser IMessageInteraction.User => User; + } +} diff --git a/src/Discord.Net.Core/Entities/Messages/MessageProperties.cs b/src/Discord.Net.Core/Entities/Messages/MessageProperties.cs index 9504e04cb..1a4eaff2d 100644 --- a/src/Discord.Net.Core/Entities/Messages/MessageProperties.cs +++ b/src/Discord.Net.Core/Entities/Messages/MessageProperties.cs @@ -1,10 +1,12 @@ +using System.Collections.Generic; + namespace Discord { /// /// Properties that are used to modify an with the specified changes. /// /// - /// The content of a message can be cleared with if and only if an + /// The content of a message can be cleared with if and only if an /// is present. /// /// @@ -17,10 +19,25 @@ public class MessageProperties /// This must be less than the constant defined by . /// public Optional Content { get; set; } + /// - /// Gets or sets the embed the message should display. + /// Gets or sets a single embed for this message. /// + /// + /// This property will be added to the array, in the future please use the array rather than this property. + /// public Optional Embed { get; set; } + + /// + /// Gets or sets the embeds of the message. + /// + public Optional Embeds { get; set; } + + /// + /// Gets or sets the components for this message. + /// + public Optional Components { get; set; } + /// /// Gets or sets the flags of the message. /// @@ -33,5 +50,10 @@ public class MessageProperties /// Gets or sets the allowed mentions of the message. /// public Optional AllowedMentions { get; set; } + + /// + /// Gets or sets the attachments for the message. + /// + public Optional> Attachments { get; set; } } } diff --git a/src/Discord.Net.Core/Entities/Messages/MessageType.cs b/src/Discord.Net.Core/Entities/Messages/MessageType.cs index bfe763cad..b83f88434 100644 --- a/src/Discord.Net.Core/Entities/Messages/MessageType.cs +++ b/src/Discord.Net.Core/Entities/Messages/MessageType.cs @@ -58,8 +58,53 @@ public enum MessageType /// ChannelFollowAdd = 12, /// + /// The message for when a guild is disqualified from discovery. + /// + GuildDiscoveryDisqualified = 14, + /// + /// The message for when a guild is requalified for discovery. + /// + GuildDiscoveryRequalified = 15, + /// + /// The message for when the initial warning is sent for the initial grace period discovery. + /// + GuildDiscoveryGracePeriodInitialWarning = 16, + /// + /// The message for when the final warning is sent for the initial grace period discovery. + /// + GuildDiscoveryGracePeriodFinalWarning = 17, + /// + /// The message for when a thread is created. + /// + ThreadCreated = 18, + /// /// The message is an inline reply. /// + /// + /// Only available in API v8. + /// Reply = 19, + /// + /// The message is an Application Command. + /// + /// + /// Only available in API v8. + /// + ApplicationCommand = 20, + /// + /// The message that starts a thread. + /// + /// + /// Only available in API v9. + /// + ThreadStarterMessage = 21, + /// + /// The message for a invite reminder. + /// + GuildInviteReminder = 22, + /// + /// The message for a context menu command. + /// + ContextMenuCommand = 23, } } diff --git a/src/Discord.Net.Core/Entities/Messages/StickerFormatType.cs b/src/Discord.Net.Core/Entities/Messages/StickerFormatType.cs new file mode 100644 index 000000000..82e6b15a4 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Messages/StickerFormatType.cs @@ -0,0 +1,25 @@ +namespace Discord +{ + /// + /// Defines the types of formats for stickers. + /// + public enum StickerFormatType + { + /// + /// Default value for a sticker format type. + /// + None = 0, + /// + /// The sticker format type is png. + /// + Png = 1, + /// + /// The sticker format type is apng. + /// + Apng = 2, + /// + /// The sticker format type is lottie. + /// + Lottie = 3 + } +} diff --git a/src/Discord.Net.Core/Entities/Messages/SticketFormatType.cs b/src/Discord.Net.Core/Entities/Messages/SticketFormatType.cs deleted file mode 100644 index d24a38534..000000000 --- a/src/Discord.Net.Core/Entities/Messages/SticketFormatType.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Discord -{ - /// Defines the types of formats for stickers. - public enum StickerFormatType - { - /// Default value for a sticker format type. - None = 0, - /// The sticker format type is png. - Png = 1, - /// The sticker format type is apng. - Apng = 2, - /// The sticker format type is lottie. - Lottie = 3, - } -} diff --git a/src/Discord.Net.Core/Entities/Messages/TimestampTag.cs b/src/Discord.Net.Core/Entities/Messages/TimestampTag.cs new file mode 100644 index 000000000..347b0daaa --- /dev/null +++ b/src/Discord.Net.Core/Entities/Messages/TimestampTag.cs @@ -0,0 +1,47 @@ +using System; + +namespace Discord +{ + /// + /// Represents a class used to make timestamps in messages. see . + /// + public class TimestampTag + { + /// + /// Gets or sets the style of the timestamp tag. + /// + public TimestampTagStyles Style { get; set; } = TimestampTagStyles.ShortDateTime; + + /// + /// Gets or sets the time for this timestamp tag. + /// + public DateTime Time { get; set; } + + /// + /// Converts the current timestamp tag to the string representation supported by discord. + /// + /// If the is null then the default 0 will be used. + /// + /// + /// A string that is compatible in a discord message, ex: <t:1625944201:f> + public override string ToString() + { + return $""; + } + + /// + /// Creates a new timestamp tag with the specified datetime object. + /// + /// The time of this timestamp tag. + /// The style for this timestamp tag. + /// The newly create timestamp tag. + public static TimestampTag FromDateTime(DateTime time, TimestampTagStyles style = TimestampTagStyles.ShortDateTime) + { + return new TimestampTag + { + Style = style, + Time = time + }; + } + } +} diff --git a/src/Discord.Net.Core/Entities/Messages/TimestampTagStyle.cs b/src/Discord.Net.Core/Entities/Messages/TimestampTagStyle.cs new file mode 100644 index 000000000..89f3c79b5 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Messages/TimestampTagStyle.cs @@ -0,0 +1,43 @@ +namespace Discord +{ + /// + /// Represents a set of styles to use with a + /// + public enum TimestampTagStyles + { + /// + /// A short time string: 16:20 + /// + ShortTime = 116, + + /// + /// A long time string: 16:20:30 + /// + LongTime = 84, + + /// + /// A short date string: 20/04/2021 + /// + ShortDate = 100, + + /// + /// A long date string: 20 April 2021 + /// + LongDate = 68, + + /// + /// A short datetime string: 20 April 2021 16:20 + /// + ShortDateTime = 102, + + /// + /// A long datetime string: Tuesday, 20 April 2021 16:20 + /// + LongDateTime = 70, + + /// + /// The relative time to the user: 2 months ago + /// + Relative = 82 + } +} diff --git a/src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissionTarget.cs b/src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissionTarget.cs new file mode 100644 index 000000000..9a99b34f1 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissionTarget.cs @@ -0,0 +1,17 @@ +namespace Discord +{ + /// + /// Specifies the target of the permission. + /// + public enum ApplicationCommandPermissionTarget + { + /// + /// The target of the permission is a role. + /// + Role = 1, + /// + /// The target of the permission is a user. + /// + User = 2 + } +} diff --git a/src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissions.cs b/src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissions.cs new file mode 100644 index 000000000..28a6455e2 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissions.cs @@ -0,0 +1,62 @@ +namespace Discord +{ + /// + /// Application command permissions allow you to enable or disable commands for specific users or roles within a guild. + /// + public class ApplicationCommandPermission + { + /// + /// The id of the role or user. + /// + public ulong TargetId { get; } + + /// + /// The target of this permission. + /// + public ApplicationCommandPermissionTarget TargetType { get; } + + /// + /// to allow, otherwise . + /// + public bool Permission { get; } + + internal ApplicationCommandPermission() { } + + /// + /// Creates a new . + /// + /// The id you want to target this permission value for. + /// The type of the targetId parameter. + /// The value of this permission. + public ApplicationCommandPermission(ulong targetId, ApplicationCommandPermissionTarget targetType, bool allow) + { + TargetId = targetId; + TargetType = targetType; + Permission = allow; + } + + /// + /// Creates a new targeting . + /// + /// The user you want to target this permission value for. + /// The value of this permission. + public ApplicationCommandPermission(IUser target, bool allow) + { + TargetId = target.Id; + Permission = allow; + TargetType = ApplicationCommandPermissionTarget.User; + } + + /// + /// Creates a new targeting . + /// + /// The role you want to target this permission value for. + /// The value of this permission. + public ApplicationCommandPermission(IRole target, bool allow) + { + TargetId = target.Id; + Permission = allow; + TargetType = ApplicationCommandPermissionTarget.Role; + } + } +} diff --git a/src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs b/src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs index bf08887bd..45e24b7fa 100644 --- a/src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs +++ b/src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs @@ -10,94 +10,141 @@ public enum ChannelPermission : ulong /// /// Allows creation of instant invites. /// - CreateInstantInvite = 0x00_00_00_01, + CreateInstantInvite = 0x00_00_00_00_01, /// /// Allows management and editing of channels. /// - ManageChannels = 0x00_00_00_10, + ManageChannels = 0x00_00_00_00_10, // Text /// /// Allows for the addition of reactions to messages. /// - AddReactions = 0x00_00_00_40, + AddReactions = 0x00_00_00_00_40, /// /// Allows guild members to view a channel, which includes reading messages in text channels. /// - ViewChannel = 0x00_00_04_00, + ViewChannel = 0x00_00_00_04_00, /// /// Allows for sending messages in a channel. /// - SendMessages = 0x00_00_08_00, + SendMessages = 0x00_00_00_08_00, /// /// Allows for sending of text-to-speech messages. /// - SendTTSMessages = 0x00_00_10_00, + SendTTSMessages = 0x00_00_00_10_00, /// /// Allows for deletion of other users messages. /// - ManageMessages = 0x00_00_20_00, + ManageMessages = 0x00_00_00_20_00, /// /// Allows links sent by users with this permission will be auto-embedded. /// - EmbedLinks = 0x00_00_40_00, + EmbedLinks = 0x00_00_00_40_00, /// /// Allows for uploading images and files. /// - AttachFiles = 0x00_00_80_00, + AttachFiles = 0x00_00_00_80_00, /// /// Allows for reading of message history. /// - ReadMessageHistory = 0x00_01_00_00, + ReadMessageHistory = 0x00_00_01_00_00, /// /// Allows for using the @everyone tag to notify all users in a channel, and the @here tag to notify all /// online users in a channel. /// - MentionEveryone = 0x00_02_00_00, + MentionEveryone = 0x00_00_02_00_00, /// /// Allows the usage of custom emojis from other servers. /// - UseExternalEmojis = 0x00_04_00_00, + UseExternalEmojis = 0x00_00_04_00_00, // Voice /// /// Allows for joining of a voice channel. /// - Connect = 0x00_10_00_00, + Connect = 0x00_00_10_00_00, /// /// Allows for speaking in a voice channel. /// - Speak = 0x00_20_00_00, + Speak = 0x00_00_20_00_00, /// /// Allows for muting members in a voice channel. /// - MuteMembers = 0x00_40_00_00, + MuteMembers = 0x00_00_40_00_00, /// /// Allows for deafening of members in a voice channel. /// - DeafenMembers = 0x00_80_00_00, + DeafenMembers = 0x00_00_80_00_00, /// /// Allows for moving of members between voice channels. /// - MoveMembers = 0x01_00_00_00, + MoveMembers = 0x00_01_00_00_00, /// /// Allows for using voice-activity-detection in a voice channel. /// - UseVAD = 0x02_00_00_00, - PrioritySpeaker = 0x00_00_01_00, + UseVAD = 0x00_02_00_00_00, + + /// + /// Allows for using priority speaker in a voice channel. + /// + PrioritySpeaker = 0x00_00_00_01_00, + /// /// Allows video streaming in a voice channel. /// - Stream = 0x00_00_02_00, + Stream = 0x00_00_00_02_00, // More General /// /// Allows management and editing of roles. /// - ManageRoles = 0x10_00_00_00, + ManageRoles = 0x00_10_00_00_00, /// /// Allows management and editing of webhooks. /// - ManageWebhooks = 0x20_00_00_00, + ManageWebhooks = 0x00_20_00_00_00, + + /// + /// Allows management and editing of emojis. + /// + ManageEmojis = 0x00_40_00_00_00, + + /// + /// Allows members to use slash commands in text channels. + /// + UseApplicationCommands = 0x00_80_00_00_00, + + /// + /// Allows for requesting to speak in stage channels. (This permission is under active development and may be changed or removed.) + /// + RequestToSpeak = 0x01_00_00_00_00, + + /// + /// Allows for deleting and archiving threads, and viewing all private threads + /// + ManageThreads = 0x04_00_00_00_00, + + /// + /// Allows for creating public threads. + /// + CreatePublicThreads = 0x08_00_00_00_00, + /// + /// Allows for creating private threads. + /// + CreatePrivateThreads = 0x10_00_00_00_00, + /// + /// Allows the usage of custom stickers from other servers. + /// + UseExternalStickers = 0x20_00_00_00_00, + /// + /// Allows for sending messages in threads. + /// + SendMessagesInThreads = 0x40_00_00_00_00, + /// + /// Allows for launching activities (applications with the EMBEDDED flag) in a voice channel. + /// + StartEmbeddedActivities = 0x80_00_00_00_00 + } } diff --git a/src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs b/src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs index d774cc51d..ee5c9984a 100644 --- a/src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs +++ b/src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs @@ -7,87 +7,106 @@ namespace Discord [DebuggerDisplay("{DebuggerDisplay,nq}")] public struct ChannelPermissions { - /// Gets a blank that grants no permissions. - /// A structure that does not contain any set permissions. + /// Gets a blank that grants no permissions. + /// A structure that does not contain any set permissions. public static readonly ChannelPermissions None = new ChannelPermissions(); - /// Gets a that grants all permissions for text channels. - public static readonly ChannelPermissions Text = new ChannelPermissions(0b01100_0000000_1111111110001_010001); - /// Gets a that grants all permissions for voice channels. - public static readonly ChannelPermissions Voice = new ChannelPermissions(0b00100_1111110_0000000011100_010001); - /// Gets a that grants all permissions for category channels. + /// Gets a that grants all permissions for text channels. + public static readonly ChannelPermissions Text = new ChannelPermissions(0b0_11111_0101100_0000000_1111111110001_010001); + /// Gets a that grants all permissions for voice channels. + public static readonly ChannelPermissions Voice = new ChannelPermissions(0b1_00000_0000100_1111110_0000000011100_010001); + /// Gets a that grants all permissions for stage channels. + public static readonly ChannelPermissions Stage = new ChannelPermissions(0b0_00000_1000100_0111010_0000000010000_010001); + /// Gets a that grants all permissions for category channels. public static readonly ChannelPermissions Category = new ChannelPermissions(0b01100_1111110_1111111110001_010001); - /// Gets a that grants all permissions for direct message channels. + /// Gets a that grants all permissions for direct message channels. public static readonly ChannelPermissions DM = new ChannelPermissions(0b00000_1000110_1011100110001_000000); - /// Gets a that grants all permissions for group channels. + /// Gets a that grants all permissions for group channels. public static readonly ChannelPermissions Group = new ChannelPermissions(0b00000_1000110_0001101100000_000000); - /// Gets a that grants all permissions for a given channel type. + /// Gets a that grants all permissions for a given channel type. /// Unknown channel type. public static ChannelPermissions All(IChannel channel) { - switch (channel) + return channel switch { - case ITextChannel _: return Text; - case IVoiceChannel _: return Voice; - case ICategoryChannel _: return Category; - case IDMChannel _: return DM; - case IGroupChannel _: return Group; - default: throw new ArgumentException(message: "Unknown channel type.", paramName: nameof(channel)); - } + ITextChannel _ => Text, + IStageChannel _ => Stage, + IVoiceChannel _ => Voice, + ICategoryChannel _ => Category, + IDMChannel _ => DM, + IGroupChannel _ => Group, + _ => throw new ArgumentException(message: "Unknown channel type.", paramName: nameof(channel)), + }; } - /// Gets a packed value representing all the permissions in this . + /// Gets a packed value representing all the permissions in this . public ulong RawValue { get; } - /// If true, a user may create invites. + /// If true, a user may create invites. public bool CreateInstantInvite => Permissions.GetValue(RawValue, ChannelPermission.CreateInstantInvite); - /// If true, a user may create, delete and modify this channel. + /// If true, a user may create, delete and modify this channel. public bool ManageChannel => Permissions.GetValue(RawValue, ChannelPermission.ManageChannels); - /// If true, a user may add reactions. + /// If true, a user may add reactions. public bool AddReactions => Permissions.GetValue(RawValue, ChannelPermission.AddReactions); - /// If true, a user may view channels. + /// If true, a user may view channels. public bool ViewChannel => Permissions.GetValue(RawValue, ChannelPermission.ViewChannel); - /// If true, a user may send messages. + /// If true, a user may send messages. public bool SendMessages => Permissions.GetValue(RawValue, ChannelPermission.SendMessages); - /// If true, a user may send text-to-speech messages. + /// If true, a user may send text-to-speech messages. public bool SendTTSMessages => Permissions.GetValue(RawValue, ChannelPermission.SendTTSMessages); - /// If true, a user may delete messages. + /// If true, a user may delete messages. public bool ManageMessages => Permissions.GetValue(RawValue, ChannelPermission.ManageMessages); - /// If true, Discord will auto-embed links sent by this user. + /// If true, Discord will auto-embed links sent by this user. public bool EmbedLinks => Permissions.GetValue(RawValue, ChannelPermission.EmbedLinks); - /// If true, a user may send files. + /// If true, a user may send files. public bool AttachFiles => Permissions.GetValue(RawValue, ChannelPermission.AttachFiles); - /// If true, a user may read previous messages. + /// If true, a user may read previous messages. public bool ReadMessageHistory => Permissions.GetValue(RawValue, ChannelPermission.ReadMessageHistory); - /// If true, a user may mention @everyone. + /// If true, a user may mention @everyone. public bool MentionEveryone => Permissions.GetValue(RawValue, ChannelPermission.MentionEveryone); - /// If true, a user may use custom emoji from other guilds. + /// If true, a user may use custom emoji from other guilds. public bool UseExternalEmojis => Permissions.GetValue(RawValue, ChannelPermission.UseExternalEmojis); - /// If true, a user may connect to a voice channel. + /// If true, a user may connect to a voice channel. public bool Connect => Permissions.GetValue(RawValue, ChannelPermission.Connect); - /// If true, a user may speak in a voice channel. + /// If true, a user may speak in a voice channel. public bool Speak => Permissions.GetValue(RawValue, ChannelPermission.Speak); - /// If true, a user may mute users. + /// If true, a user may mute users. public bool MuteMembers => Permissions.GetValue(RawValue, ChannelPermission.MuteMembers); - /// If true, a user may deafen users. + /// If true, a user may deafen users. public bool DeafenMembers => Permissions.GetValue(RawValue, ChannelPermission.DeafenMembers); - /// If true, a user may move other users between voice channels. + /// If true, a user may move other users between voice channels. public bool MoveMembers => Permissions.GetValue(RawValue, ChannelPermission.MoveMembers); - /// If true, a user may use voice-activity-detection rather than push-to-talk. + /// If true, a user may use voice-activity-detection rather than push-to-talk. public bool UseVAD => Permissions.GetValue(RawValue, ChannelPermission.UseVAD); - /// If true, a user may use priority speaker in a voice channel. + /// If true, a user may use priority speaker in a voice channel. public bool PrioritySpeaker => Permissions.GetValue(RawValue, ChannelPermission.PrioritySpeaker); - /// If true, a user may stream video in a voice channel. + /// If true, a user may stream video in a voice channel. public bool Stream => Permissions.GetValue(RawValue, ChannelPermission.Stream); - /// If true, a user may adjust role permissions. This also implictly grants all other permissions. + /// If true, a user may adjust role permissions. This also implicitly grants all other permissions. public bool ManageRoles => Permissions.GetValue(RawValue, ChannelPermission.ManageRoles); - /// If true, a user may edit the webhooks for this channel. + /// If true, a user may edit the webhooks for this channel. public bool ManageWebhooks => Permissions.GetValue(RawValue, ChannelPermission.ManageWebhooks); + /// If true, a user may use application commands in this guild. + public bool UseApplicationCommands => Permissions.GetValue(RawValue, ChannelPermission.UseApplicationCommands); + /// If true, a user may request to speak in stage channels. + public bool RequestToSpeak => Permissions.GetValue(RawValue, ChannelPermission.RequestToSpeak); + /// If true, a user may manage threads in this guild. + public bool ManageThreads => Permissions.GetValue(RawValue, ChannelPermission.ManageThreads); + /// If true, a user may create public threads in this guild. + public bool CreatePublicThreads => Permissions.GetValue(RawValue, ChannelPermission.CreatePublicThreads); + /// If true, a user may create private threads in this guild. + public bool CreatePrivateThreads => Permissions.GetValue(RawValue, ChannelPermission.CreatePrivateThreads); + /// If true, a user may use external stickers in this guild. + public bool UseExternalStickers => Permissions.GetValue(RawValue, ChannelPermission.UseExternalStickers); + /// If true, a user may send messages in threads in this guild. + public bool SendMessagesInThreads => Permissions.GetValue(RawValue, ChannelPermission.SendMessagesInThreads); + /// If true, a user launch application activities in voice channels in this guild. + public bool StartEmbeddedActivities => Permissions.GetValue(RawValue, ChannelPermission.StartEmbeddedActivities); - /// Creates a new with the provided packed value. + /// Creates a new with the provided packed value. public ChannelPermissions(ulong rawValue) { RawValue = rawValue; } private ChannelPermissions(ulong initialValue, @@ -112,7 +131,15 @@ private ChannelPermissions(ulong initialValue, bool? prioritySpeaker = null, bool? stream = null, bool? manageRoles = null, - bool? manageWebhooks = null) + bool? manageWebhooks = null, + bool? useApplicationCommands = null, + bool? requestToSpeak = null, + bool? manageThreads = null, + bool? createPublicThreads = null, + bool? createPrivateThreads = null, + bool? useExternalStickers = null, + bool? sendMessagesInThreads = null, + bool? startEmbeddedActivities = null) { ulong value = initialValue; @@ -138,11 +165,19 @@ private ChannelPermissions(ulong initialValue, Permissions.SetValue(ref value, stream, ChannelPermission.Stream); Permissions.SetValue(ref value, manageRoles, ChannelPermission.ManageRoles); Permissions.SetValue(ref value, manageWebhooks, ChannelPermission.ManageWebhooks); + Permissions.SetValue(ref value, useApplicationCommands, ChannelPermission.UseApplicationCommands); + Permissions.SetValue(ref value, requestToSpeak, ChannelPermission.RequestToSpeak); + Permissions.SetValue(ref value, manageThreads, ChannelPermission.ManageThreads); + Permissions.SetValue(ref value, createPublicThreads, ChannelPermission.CreatePublicThreads); + Permissions.SetValue(ref value, createPrivateThreads, ChannelPermission.CreatePrivateThreads); + Permissions.SetValue(ref value, useExternalStickers, ChannelPermission.UseExternalStickers); + Permissions.SetValue(ref value, sendMessagesInThreads, ChannelPermission.SendMessagesInThreads); + Permissions.SetValue(ref value, startEmbeddedActivities, ChannelPermission.StartEmbeddedActivities); RawValue = value; } - /// Creates a new with the provided permissions. + /// Creates a new with the provided permissions. public ChannelPermissions( bool createInstantInvite = false, bool manageChannel = false, @@ -165,13 +200,23 @@ public ChannelPermissions( bool prioritySpeaker = false, bool stream = false, bool manageRoles = false, - bool manageWebhooks = false) + bool manageWebhooks = false, + bool useApplicationCommands = false, + bool requestToSpeak = false, + bool manageThreads = false, + bool createPublicThreads = false, + bool createPrivateThreads = false, + bool useExternalStickers = false, + bool sendMessagesInThreads = false, + bool startEmbeddedActivities = false) : this(0, createInstantInvite, manageChannel, addReactions, viewChannel, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, readMessageHistory, mentionEveryone, useExternalEmojis, connect, - speak, muteMembers, deafenMembers, moveMembers, useVoiceActivation, prioritySpeaker, stream, manageRoles, manageWebhooks) + speak, muteMembers, deafenMembers, moveMembers, useVoiceActivation, prioritySpeaker, stream, manageRoles, manageWebhooks, + useApplicationCommands, requestToSpeak, manageThreads, createPublicThreads, createPrivateThreads, useExternalStickers, sendMessagesInThreads, + startEmbeddedActivities) { } - /// Creates a new from this one, changing the provided non-null permissions. + /// Creates a new from this one, changing the provided non-null permissions. public ChannelPermissions Modify( bool? createInstantInvite = null, bool? manageChannel = null, @@ -194,7 +239,15 @@ public ChannelPermissions Modify( bool? prioritySpeaker = null, bool? stream = null, bool? manageRoles = null, - bool? manageWebhooks = null) + bool? manageWebhooks = null, + bool? useApplicationCommands = null, + bool? requestToSpeak = null, + bool? manageThreads = null, + bool? createPublicThreads = null, + bool? createPrivateThreads = null, + bool? useExternalStickers = null, + bool? sendMessagesInThreads = null, + bool? startEmbeddedActivities = null) => new ChannelPermissions(RawValue, createInstantInvite, manageChannel, @@ -217,7 +270,15 @@ public ChannelPermissions Modify( prioritySpeaker, stream, manageRoles, - manageWebhooks); + manageWebhooks, + useApplicationCommands, + requestToSpeak, + manageThreads, + createPublicThreads, + createPrivateThreads, + useExternalStickers, + sendMessagesInThreads, + startEmbeddedActivities); public bool Has(ChannelPermission permission) => Permissions.GetValue(RawValue, permission); diff --git a/src/Discord.Net.Core/Entities/Permissions/GuildApplicationCommandPermissions.cs b/src/Discord.Net.Core/Entities/Permissions/GuildApplicationCommandPermissions.cs new file mode 100644 index 000000000..e738fec4c --- /dev/null +++ b/src/Discord.Net.Core/Entities/Permissions/GuildApplicationCommandPermissions.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; + +namespace Discord +{ + /// + /// Returned when fetching the permissions for a command in a guild. + /// + public class GuildApplicationCommandPermission + + { + /// + /// The id of the command. + /// + public ulong CommandId { get; } + + /// + /// The id of the application the command belongs to. + /// + public ulong ApplicationId { get; } + + /// + /// The id of the guild. + /// + public ulong GuildId { get; } + + /// + /// The permissions for the command in the guild. + /// + public IReadOnlyCollection Permissions { get; } + + internal GuildApplicationCommandPermission(ulong commandId, ulong appId, ulong guildId, ApplicationCommandPermission[] permissions) + { + CommandId = commandId; + ApplicationId = appId; + GuildId = guildId; + Permissions = permissions; + } + } +} diff --git a/src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs b/src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs index 31bd6164a..5a5827c1d 100644 --- a/src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs +++ b/src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs @@ -10,7 +10,7 @@ public enum GuildPermission : ulong /// /// Allows creation of instant invites. /// - CreateInstantInvite = 0x00_00_00_01, + CreateInstantInvite = 0x00_00_00_01, /// /// Allows kicking members. /// @@ -18,7 +18,7 @@ public enum GuildPermission : ulong /// This permission requires the owner account to use two-factor /// authentication when used on a guild that has server-wide 2FA enabled. /// - KickMembers = 0x00_00_00_02, + KickMembers = 0x00_00_00_02, /// /// Allows banning members. /// @@ -26,7 +26,7 @@ public enum GuildPermission : ulong /// This permission requires the owner account to use two-factor /// authentication when used on a guild that has server-wide 2FA enabled. /// - BanMembers = 0x00_00_00_04, + BanMembers = 0x00_00_00_04, /// /// Allows all permissions and bypasses channel permission overwrites. /// @@ -34,7 +34,7 @@ public enum GuildPermission : ulong /// This permission requires the owner account to use two-factor /// authentication when used on a guild that has server-wide 2FA enabled. /// - Administrator = 0x00_00_00_08, + Administrator = 0x00_00_00_08, /// /// Allows management and editing of channels. /// @@ -42,7 +42,7 @@ public enum GuildPermission : ulong /// This permission requires the owner account to use two-factor /// authentication when used on a guild that has server-wide 2FA enabled. /// - ManageChannels = 0x00_00_00_10, + ManageChannels = 0x00_00_00_10, /// /// Allows management and editing of the guild. /// @@ -50,27 +50,33 @@ public enum GuildPermission : ulong /// This permission requires the owner account to use two-factor /// authentication when used on a guild that has server-wide 2FA enabled. /// - ManageGuild = 0x00_00_00_20, + ManageGuild = 0x00_00_00_20, /// /// Allows for viewing of guild insights /// - ViewGuildInsights = 0x00_08_00_00, + ViewGuildInsights = 0x00_08_00_00, // Text /// /// Allows for the addition of reactions to messages. /// - AddReactions = 0x00_00_00_40, + AddReactions = 0x00_00_00_40, /// /// Allows for viewing of audit logs. /// - ViewAuditLog = 0x00_00_00_80, - ViewChannel = 0x00_00_04_00, - SendMessages = 0x00_00_08_00, + ViewAuditLog = 0x00_00_00_80, + /// + /// Allows guild members to view a channel, which includes reading messages in text channels. + /// + ViewChannel = 0x00_00_04_00, + /// + /// Allows for sending messages in a channel + /// + SendMessages = 0x00_00_08_00, /// /// Allows for sending of text-to-speech messages. /// - SendTTSMessages = 0x00_00_10_00, + SendTTSMessages = 0x00_00_10_00, /// /// Allows for deletion of other users messages. /// @@ -78,70 +84,73 @@ public enum GuildPermission : ulong /// This permission requires the owner account to use two-factor /// authentication when used on a guild that has server-wide 2FA enabled. /// - ManageMessages = 0x00_00_20_00, + ManageMessages = 0x00_00_20_00, /// /// Allows links sent by users with this permission will be auto-embedded. /// - EmbedLinks = 0x00_00_40_00, + EmbedLinks = 0x00_00_40_00, /// /// Allows for uploading images and files. /// - AttachFiles = 0x00_00_80_00, + AttachFiles = 0x00_00_80_00, /// /// Allows for reading of message history. /// - ReadMessageHistory = 0x00_01_00_00, + ReadMessageHistory = 0x00_01_00_00, /// /// Allows for using the @everyone tag to notify all users in a channel, and the @here tag to notify all /// online users in a channel. /// - MentionEveryone = 0x00_02_00_00, + MentionEveryone = 0x00_02_00_00, /// /// Allows the usage of custom emojis from other servers. /// - UseExternalEmojis = 0x00_04_00_00, + UseExternalEmojis = 0x00_04_00_00, // Voice /// /// Allows for joining of a voice channel. /// - Connect = 0x00_10_00_00, + Connect = 0x00_10_00_00, /// /// Allows for speaking in a voice channel. /// - Speak = 0x00_20_00_00, + Speak = 0x00_20_00_00, /// /// Allows for muting members in a voice channel. /// - MuteMembers = 0x00_40_00_00, + MuteMembers = 0x00_40_00_00, /// /// Allows for deafening of members in a voice channel. /// - DeafenMembers = 0x00_80_00_00, + DeafenMembers = 0x00_80_00_00, /// /// Allows for moving of members between voice channels. /// - MoveMembers = 0x01_00_00_00, + MoveMembers = 0x01_00_00_00, /// /// Allows for using voice-activity-detection in a voice channel. /// - UseVAD = 0x02_00_00_00, - PrioritySpeaker = 0x00_00_01_00, + UseVAD = 0x02_00_00_00, + /// + /// Allows for using priority speaker in a voice channel. + /// + PrioritySpeaker = 0x00_00_01_00, /// /// Allows video streaming in a voice channel. /// - Stream = 0x00_00_02_00, + Stream = 0x00_00_02_00, // General 2 /// /// Allows for modification of own nickname. /// - ChangeNickname = 0x04_00_00_00, + ChangeNickname = 0x04_00_00_00, /// /// Allows for modification of other users nicknames. /// - ManageNicknames = 0x08_00_00_00, + ManageNicknames = 0x08_00_00_00, /// /// Allows management and editing of roles. /// @@ -149,7 +158,7 @@ public enum GuildPermission : ulong /// This permission requires the owner account to use two-factor /// authentication when used on a guild that has server-wide 2FA enabled. /// - ManageRoles = 0x10_00_00_00, + ManageRoles = 0x10_00_00_00, /// /// Allows management and editing of webhooks. /// @@ -157,14 +166,55 @@ public enum GuildPermission : ulong /// This permission requires the owner account to use two-factor /// authentication when used on a guild that has server-wide 2FA enabled. /// - ManageWebhooks = 0x20_00_00_00, + ManageWebhooks = 0x20_00_00_00, /// - /// Allows management and editing of emojis. + /// Allows management and editing of emojis and stickers. /// /// /// This permission requires the owner account to use two-factor /// authentication when used on a guild that has server-wide 2FA enabled. /// - ManageEmojis = 0x40_00_00_00 + ManageEmojisAndStickers = 0x40_00_00_00, + /// + /// Allows members to use application commands like slash commands and context menus in text channels. + /// + UseApplicationCommands = 0x80_00_00_00, + /// + /// Allows for requesting to speak in stage channels. + /// + RequestToSpeak = 0x01_00_00_00_00, + /// + /// Allows for creating, editing, and deleting guild scheduled events. + /// + ManageEvents = 0x02_00_00_00_00, + /// + /// Allows for deleting and archiving threads, and viewing all private threads. + /// + /// + /// This permission requires the owner account to use two-factor + /// authentication when used on a guild that has server-wide 2FA enabled. + /// + ManageThreads = 0x04_00_00_00_00, + /// + /// Allows for creating public threads. + /// + CreatePublicThreads = 0x08_00_00_00_00, + /// + /// Allows for creating private threads. + /// + CreatePrivateThreads = 0x10_00_00_00_00, + /// + /// Allows the usage of custom stickers from other servers. + /// + UseExternalStickers = 0x20_00_00_00_00, + /// + /// Allows for sending messages in threads. + /// + SendMessagesInThreads = 0x40_00_00_00_00, + /// + /// Allows for launching activities (applications with the EMBEDDED flag) in a voice channel. + /// + StartEmbeddedActivities = 0x80_00_00_00_00 + } } diff --git a/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs b/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs index b03c0e1a8..8a4ad2189 100644 --- a/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs +++ b/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; namespace Discord { @@ -10,9 +11,9 @@ public struct GuildPermissions /// Gets a blank that grants no permissions. public static readonly GuildPermissions None = new GuildPermissions(); /// Gets a that grants all guild permissions for webhook users. - public static readonly GuildPermissions Webhook = new GuildPermissions(0b00000_0000000_0001101100000_000000); + public static readonly GuildPermissions Webhook = new GuildPermissions(0b0_00000_0000000_0000000_0001101100000_000000); /// Gets a that grants all guild permissions. - public static readonly GuildPermissions All = new GuildPermissions(0b11111_1111111_1111111111111_111111); + public static readonly GuildPermissions All = new GuildPermissions(0b1_11111_1111111_1111111_1111111111111_111111); /// Gets a packed value representing all the permissions in this . public ulong RawValue { get; } @@ -81,8 +82,26 @@ public struct GuildPermissions public bool ManageRoles => Permissions.GetValue(RawValue, GuildPermission.ManageRoles); /// If true, a user may edit the webhooks for this guild. public bool ManageWebhooks => Permissions.GetValue(RawValue, GuildPermission.ManageWebhooks); - /// If true, a user may edit the emojis for this guild. - public bool ManageEmojis => Permissions.GetValue(RawValue, GuildPermission.ManageEmojis); + /// If true, a user may edit the emojis and stickers for this guild. + public bool ManageEmojisAndStickers => Permissions.GetValue(RawValue, GuildPermission.ManageEmojisAndStickers); + /// If true, a user may use slash commands in this guild. + public bool UseApplicationCommands => Permissions.GetValue(RawValue, GuildPermission.UseApplicationCommands); + /// If true, a user may request to speak in stage channels. + public bool RequestToSpeak => Permissions.GetValue(RawValue, GuildPermission.RequestToSpeak); + /// If true, a user may create, edit, and delete events. + public bool ManageEvents => Permissions.GetValue(RawValue, GuildPermission.ManageEvents); + /// If true, a user may manage threads in this guild. + public bool ManageThreads => Permissions.GetValue(RawValue, GuildPermission.ManageThreads); + /// If true, a user may create public threads in this guild. + public bool CreatePublicThreads => Permissions.GetValue(RawValue, GuildPermission.CreatePublicThreads); + /// If true, a user may create private threads in this guild. + public bool CreatePrivateThreads => Permissions.GetValue(RawValue, GuildPermission.CreatePrivateThreads); + /// If true, a user may use external stickers in this guild. + public bool UseExternalStickers => Permissions.GetValue(RawValue, GuildPermission.UseExternalStickers); + /// If true, a user may send messages in threads in this guild. + public bool SendMessagesInThreads => Permissions.GetValue(RawValue, GuildPermission.SendMessagesInThreads); + /// If true, a user launch application activities in voice channels in this guild. + public bool StartEmbeddedActivities => Permissions.GetValue(RawValue, GuildPermission.StartEmbeddedActivities); /// Creates a new with the provided packed value. public GuildPermissions(ulong rawValue) { RawValue = rawValue; } @@ -121,7 +140,16 @@ private GuildPermissions(ulong initialValue, bool? manageNicknames = null, bool? manageRoles = null, bool? manageWebhooks = null, - bool? manageEmojis = null) + bool? manageEmojisAndStickers = null, + bool? useApplicationCommands = null, + bool? requestToSpeak = null, + bool? manageEvents = null, + bool? manageThreads = null, + bool? createPublicThreads = null, + bool? createPrivateThreads = null, + bool? useExternalStickers = null, + bool? sendMessagesInThreads = null, + bool? startEmbeddedActivities = null) { ulong value = initialValue; @@ -155,7 +183,16 @@ private GuildPermissions(ulong initialValue, Permissions.SetValue(ref value, manageNicknames, GuildPermission.ManageNicknames); Permissions.SetValue(ref value, manageRoles, GuildPermission.ManageRoles); Permissions.SetValue(ref value, manageWebhooks, GuildPermission.ManageWebhooks); - Permissions.SetValue(ref value, manageEmojis, GuildPermission.ManageEmojis); + Permissions.SetValue(ref value, manageEmojisAndStickers, GuildPermission.ManageEmojisAndStickers); + Permissions.SetValue(ref value, useApplicationCommands, GuildPermission.UseApplicationCommands); + Permissions.SetValue(ref value, requestToSpeak, GuildPermission.RequestToSpeak); + Permissions.SetValue(ref value, manageEvents, GuildPermission.ManageEvents); + Permissions.SetValue(ref value, manageThreads, GuildPermission.ManageThreads); + Permissions.SetValue(ref value, createPublicThreads, GuildPermission.CreatePublicThreads); + Permissions.SetValue(ref value, createPrivateThreads, GuildPermission.CreatePrivateThreads); + Permissions.SetValue(ref value, useExternalStickers, GuildPermission.UseExternalStickers); + Permissions.SetValue(ref value, sendMessagesInThreads, GuildPermission.SendMessagesInThreads); + Permissions.SetValue(ref value, startEmbeddedActivities, GuildPermission.StartEmbeddedActivities); RawValue = value; } @@ -192,7 +229,16 @@ public GuildPermissions( bool manageNicknames = false, bool manageRoles = false, bool manageWebhooks = false, - bool manageEmojis = false) + bool manageEmojisAndStickers = false, + bool useApplicationCommands = false, + bool requestToSpeak = false, + bool manageEvents = false, + bool manageThreads = false, + bool createPublicThreads = false, + bool createPrivateThreads = false, + bool useExternalStickers = false, + bool sendMessagesInThreads = false, + bool startEmbeddedActivities = false) : this(0, createInstantInvite: createInstantInvite, manageRoles: manageRoles, @@ -224,7 +270,16 @@ public GuildPermissions( changeNickname: changeNickname, manageNicknames: manageNicknames, manageWebhooks: manageWebhooks, - manageEmojis: manageEmojis) + manageEmojisAndStickers: manageEmojisAndStickers, + useApplicationCommands: useApplicationCommands, + requestToSpeak: requestToSpeak, + manageEvents: manageEvents, + manageThreads: manageThreads, + createPublicThreads: createPublicThreads, + createPrivateThreads: createPrivateThreads, + useExternalStickers: useExternalStickers, + sendMessagesInThreads: sendMessagesInThreads, + startEmbeddedActivities: startEmbeddedActivities) { } /// Creates a new from this one, changing the provided non-null permissions. @@ -259,11 +314,22 @@ public GuildPermissions Modify( bool? manageNicknames = null, bool? manageRoles = null, bool? manageWebhooks = null, - bool? manageEmojis = null) + bool? manageEmojisAndStickers = null, + bool? useApplicationCommands = null, + bool? requestToSpeak = null, + bool? manageEvents = null, + bool? manageThreads = null, + bool? createPublicThreads = null, + bool? createPrivateThreads = null, + bool? useExternalStickers = null, + bool? sendMessagesInThreads = null, + bool? startEmbeddedActivities = null) => new GuildPermissions(RawValue, createInstantInvite, kickMembers, banMembers, administrator, manageChannels, manageGuild, addReactions, viewAuditLog, viewGuildInsights, viewChannel, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers, moveMembers, - useVoiceActivation, prioritySpeaker, stream, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojis); + useVoiceActivation, prioritySpeaker, stream, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojisAndStickers, + useApplicationCommands, requestToSpeak, manageEvents, manageThreads, createPublicThreads, createPrivateThreads, useExternalStickers, sendMessagesInThreads, + startEmbeddedActivities); /// /// Returns a value that indicates if a specific is enabled @@ -293,6 +359,18 @@ public List ToList() return perms; } + internal void Ensure(GuildPermission permissions) + { + if (!Has(permissions)) + { + var vals = Enum.GetValues(typeof(GuildPermission)).Cast(); + var currentValues = RawValue; + var missingValues = vals.Where(x => permissions.HasFlag(x) && !Permissions.GetValue(currentValues, x)); + + throw new InvalidOperationException($"Missing required guild permission{(missingValues.Count() > 1 ? "s" : "")} {string.Join(", ", missingValues.Select(x => x.ToString()))} in order to execute this operation."); + } + } + public override string ToString() => RawValue.ToString(); private string DebuggerDisplay => $"{string.Join(", ", ToList())}"; } diff --git a/src/Discord.Net.Core/Entities/Permissions/OverwritePermissions.cs b/src/Discord.Net.Core/Entities/Permissions/OverwritePermissions.cs index 4f144c74b..0e634ad1a 100644 --- a/src/Discord.Net.Core/Entities/Permissions/OverwritePermissions.cs +++ b/src/Discord.Net.Core/Entities/Permissions/OverwritePermissions.cs @@ -1,3 +1,4 @@ +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Diagnostics; @@ -82,6 +83,22 @@ public static OverwritePermissions DenyAll(IChannel channel) public PermValue ManageRoles => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ManageRoles); /// If True, a user may edit the webhooks for this channel. public PermValue ManageWebhooks => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ManageWebhooks); + /// If true, a user may use slash commands in this guild. + public PermValue UseApplicationCommands => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.UseApplicationCommands); + /// If true, a user may request to speak in stage channels. + public PermValue RequestToSpeak => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.RequestToSpeak); + /// If true, a user may manage threads in this guild. + public PermValue ManageThreads => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ManageThreads); + /// If true, a user may create public threads in this guild. + public PermValue CreatePublicThreads => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.CreatePublicThreads); + /// If true, a user may create private threads in this guild. + public PermValue CreatePrivateThreads => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.CreatePrivateThreads); + /// If true, a user may use external stickers in this guild. + public PermValue UseExternalStickers => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.UseExternalStickers); + /// If true, a user may send messages in threads in this guild. + public PermValue SendMessagesInThreads => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.SendMessagesInThreads); + /// If true, a user launch application activities in voice channels in this guild. + public PermValue StartEmbeddedActivities => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.StartEmbeddedActivities); /// Creates a new OverwritePermissions with the provided allow and deny packed values. public OverwritePermissions(ulong allowValue, ulong denyValue) @@ -119,7 +136,18 @@ private OverwritePermissions(ulong allowValue, ulong denyValue, PermValue? manageRoles = null, PermValue? manageWebhooks = null, PermValue? prioritySpeaker = null, - PermValue? stream = null) + PermValue? stream = null, + PermValue? useSlashCommands = null, + PermValue? useApplicationCommands = null, + PermValue? requestToSpeak = null, + PermValue? manageThreads = null, + PermValue? createPublicThreads = null, + PermValue? createPrivateThreads = null, + PermValue? usePublicThreads = null, + PermValue? usePrivateThreads = null, + PermValue? useExternalStickers = null, + PermValue? sendMessagesInThreads = null, + PermValue? startEmbeddedActivities = null) { Permissions.SetValue(ref allowValue, ref denyValue, createInstantInvite, ChannelPermission.CreateInstantInvite); Permissions.SetValue(ref allowValue, ref denyValue, manageChannel, ChannelPermission.ManageChannels); @@ -143,6 +171,14 @@ private OverwritePermissions(ulong allowValue, ulong denyValue, Permissions.SetValue(ref allowValue, ref denyValue, stream, ChannelPermission.Stream); Permissions.SetValue(ref allowValue, ref denyValue, manageRoles, ChannelPermission.ManageRoles); Permissions.SetValue(ref allowValue, ref denyValue, manageWebhooks, ChannelPermission.ManageWebhooks); + Permissions.SetValue(ref allowValue, ref denyValue, useApplicationCommands, ChannelPermission.UseApplicationCommands); + Permissions.SetValue(ref allowValue, ref denyValue, requestToSpeak, ChannelPermission.RequestToSpeak); + Permissions.SetValue(ref allowValue, ref denyValue, manageThreads, ChannelPermission.ManageThreads); + Permissions.SetValue(ref allowValue, ref denyValue, createPublicThreads, ChannelPermission.CreatePublicThreads); + Permissions.SetValue(ref allowValue, ref denyValue, createPrivateThreads, ChannelPermission.CreatePrivateThreads); + Permissions.SetValue(ref allowValue, ref denyValue, useExternalStickers, ChannelPermission.UseExternalStickers); + Permissions.SetValue(ref allowValue, ref denyValue, sendMessagesInThreads, ChannelPermission.SendMessagesInThreads); + Permissions.SetValue(ref allowValue, ref denyValue, startEmbeddedActivities, ChannelPermission.StartEmbeddedActivities); AllowValue = allowValue; DenyValue = denyValue; @@ -173,10 +209,23 @@ public OverwritePermissions( PermValue manageRoles = PermValue.Inherit, PermValue manageWebhooks = PermValue.Inherit, PermValue prioritySpeaker = PermValue.Inherit, - PermValue stream = PermValue.Inherit) + PermValue stream = PermValue.Inherit, + PermValue useSlashCommands = PermValue.Inherit, + PermValue useApplicationCommands = PermValue.Inherit, + PermValue requestToSpeak = PermValue.Inherit, + PermValue manageThreads = PermValue.Inherit, + PermValue createPublicThreads = PermValue.Inherit, + PermValue createPrivateThreads = PermValue.Inherit, + PermValue usePublicThreads = PermValue.Inherit, + PermValue usePrivateThreads = PermValue.Inherit, + PermValue useExternalStickers = PermValue.Inherit, + PermValue sendMessagesInThreads = PermValue.Inherit, + PermValue startEmbeddedActivities = PermValue.Inherit) : this(0, 0, createInstantInvite, manageChannel, addReactions, viewChannel, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers, - moveMembers, useVoiceActivation, manageRoles, manageWebhooks, prioritySpeaker, stream) { } + moveMembers, useVoiceActivation, manageRoles, manageWebhooks, prioritySpeaker, stream, useSlashCommands, useApplicationCommands, + requestToSpeak, manageThreads, createPublicThreads, createPrivateThreads, usePublicThreads, usePrivateThreads, useExternalStickers, + sendMessagesInThreads, startEmbeddedActivities) { } /// /// Initializes a new from the current one, changing the provided @@ -204,10 +253,23 @@ public OverwritePermissions Modify( PermValue? manageRoles = null, PermValue? manageWebhooks = null, PermValue? prioritySpeaker = null, - PermValue? stream = null) + PermValue? stream = null, + PermValue? useSlashCommands = null, + PermValue? useApplicationCommands = null, + PermValue? requestToSpeak = null, + PermValue? manageThreads = null, + PermValue? createPublicThreads = null, + PermValue? createPrivateThreads = null, + PermValue? usePublicThreads = null, + PermValue? usePrivateThreads = null, + PermValue? useExternalStickers = null, + PermValue? sendMessagesInThreads = null, + PermValue? startEmbeddedActivities = null) => new OverwritePermissions(AllowValue, DenyValue, createInstantInvite, manageChannel, addReactions, viewChannel, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers, - moveMembers, useVoiceActivation, manageRoles, manageWebhooks, prioritySpeaker, stream); + moveMembers, useVoiceActivation, manageRoles, manageWebhooks, prioritySpeaker, stream, useSlashCommands, useApplicationCommands, + requestToSpeak, manageThreads, createPublicThreads, createPrivateThreads, usePublicThreads, usePrivateThreads, useExternalStickers, + sendMessagesInThreads, startEmbeddedActivities); /// /// Creates a of all the values that are allowed. diff --git a/src/Discord.Net.Core/Entities/Roles/Color.cs b/src/Discord.Net.Core/Entities/Roles/Color.cs index 7c2d152a4..ee50710e8 100644 --- a/src/Discord.Net.Core/Entities/Roles/Color.cs +++ b/src/Discord.Net.Core/Entities/Roles/Color.cs @@ -10,68 +10,70 @@ namespace Discord [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public struct Color { + /// Gets the max decimal value of color. + public const uint MaxDecimalValue = 0xFFFFFF; /// Gets the default user color value. - public static readonly Color Default = new Color(0); + public static readonly Color Default = new(0); /// Gets the teal color value. /// A color struct with the hex value of 1ABC9C. - public static readonly Color Teal = new Color(0x1ABC9C); + public static readonly Color Teal = new(0x1ABC9C); /// Gets the dark teal color value. /// A color struct with the hex value of 11806A. - public static readonly Color DarkTeal = new Color(0x11806A); + public static readonly Color DarkTeal = new(0x11806A); /// Gets the green color value. /// A color struct with the hex value of 2ECC71. - public static readonly Color Green = new Color(0x2ECC71); + public static readonly Color Green = new(0x2ECC71); /// Gets the dark green color value. /// A color struct with the hex value of 1F8B4C. - public static readonly Color DarkGreen = new Color(0x1F8B4C); + public static readonly Color DarkGreen = new(0x1F8B4C); /// Gets the blue color value. /// A color struct with the hex value of 3498DB. - public static readonly Color Blue = new Color(0x3498DB); + public static readonly Color Blue = new(0x3498DB); /// Gets the dark blue color value. /// A color struct with the hex value of 206694. - public static readonly Color DarkBlue = new Color(0x206694); + public static readonly Color DarkBlue = new(0x206694); /// Gets the purple color value. /// A color struct with the hex value of 9B59B6. - public static readonly Color Purple = new Color(0x9B59B6); + public static readonly Color Purple = new(0x9B59B6); /// Gets the dark purple color value. /// A color struct with the hex value of 71368A. - public static readonly Color DarkPurple = new Color(0x71368A); + public static readonly Color DarkPurple = new(0x71368A); /// Gets the magenta color value. /// A color struct with the hex value of E91E63. - public static readonly Color Magenta = new Color(0xE91E63); + public static readonly Color Magenta = new(0xE91E63); /// Gets the dark magenta color value. /// A color struct with the hex value of AD1457. - public static readonly Color DarkMagenta = new Color(0xAD1457); + public static readonly Color DarkMagenta = new(0xAD1457); /// Gets the gold color value. /// A color struct with the hex value of F1C40F. - public static readonly Color Gold = new Color(0xF1C40F); + public static readonly Color Gold = new(0xF1C40F); /// Gets the light orange color value. /// A color struct with the hex value of C27C0E. - public static readonly Color LightOrange = new Color(0xC27C0E); + public static readonly Color LightOrange = new(0xC27C0E); /// Gets the orange color value. /// A color struct with the hex value of E67E22. - public static readonly Color Orange = new Color(0xE67E22); + public static readonly Color Orange = new(0xE67E22); /// Gets the dark orange color value. /// A color struct with the hex value of A84300. - public static readonly Color DarkOrange = new Color(0xA84300); + public static readonly Color DarkOrange = new(0xA84300); /// Gets the red color value. /// A color struct with the hex value of E74C3C. - public static readonly Color Red = new Color(0xE74C3C); + public static readonly Color Red = new(0xE74C3C); /// Gets the dark red color value. /// A color struct with the hex value of 992D22. - public static readonly Color DarkRed = new Color(0x992D22); + public static readonly Color DarkRed = new(0x992D22); /// Gets the light grey color value. /// A color struct with the hex value of 979C9F. - public static readonly Color LightGrey = new Color(0x979C9F); + public static readonly Color LightGrey = new(0x979C9F); /// Gets the lighter grey color value. /// A color struct with the hex value of 95A5A6. - public static readonly Color LighterGrey = new Color(0x95A5A6); + public static readonly Color LighterGrey = new(0x95A5A6); /// Gets the dark grey color value. /// A color struct with the hex value of 607D8B. - public static readonly Color DarkGrey = new Color(0x607D8B); + public static readonly Color DarkGrey = new(0x607D8B); /// Gets the darker grey color value. /// A color struct with the hex value of 546E7A. - public static readonly Color DarkerGrey = new Color(0x546E7A); + public static readonly Color DarkerGrey = new(0x546E7A); /// Gets the encoded value for this color. /// @@ -91,22 +93,27 @@ public struct Color /// Initializes a struct with the given raw value. /// /// - /// The following will create a color that has a hex value of + /// The following will create a color that has a hex value of /// #607D8B. /// /// Color darkGrey = new Color(0x607D8B); /// /// /// The raw value of the color (e.g. 0x607D8B). + /// Value exceeds . public Color(uint rawValue) { + if (rawValue > MaxDecimalValue) + throw new ArgumentException($"{nameof(RawValue)} of color cannot be greater than {MaxDecimalValue}!", nameof(rawValue)); + RawValue = rawValue; } + /// /// Initializes a struct with the given RGB bytes. /// /// - /// The following will create a color that has a value of + /// The following will create a color that has a value of /// #607D8B. /// /// Color darkGrey = new Color((byte)0b_01100000, (byte)0b_01111101, (byte)0b_10001011); @@ -115,19 +122,24 @@ public Color(uint rawValue) /// The byte that represents the red color. /// The byte that represents the green color. /// The byte that represents the blue color. + /// Value exceeds . public Color(byte r, byte g, byte b) { - RawValue = - ((uint)r << 16) | - ((uint)g << 8) | - (uint)b; + uint value = ((uint)r << 16) + | ((uint)g << 8) + | (uint)b; + + if (value > MaxDecimalValue) + throw new ArgumentException($"{nameof(RawValue)} of color cannot be greater than {MaxDecimalValue}!"); + + RawValue = value; } /// /// Initializes a struct with the given RGB value. /// /// - /// The following will create a color that has a value of + /// The following will create a color that has a value of /// #607D8B. /// /// Color darkGrey = new Color(96, 125, 139); @@ -145,16 +157,15 @@ public Color(int r, int g, int b) throw new ArgumentOutOfRangeException(nameof(g), "Value must be within [0,255]."); if (b < 0 || b > 255) throw new ArgumentOutOfRangeException(nameof(b), "Value must be within [0,255]."); - RawValue = - ((uint)r << 16) | - ((uint)g << 8) | - (uint)b; + RawValue = ((uint)r << 16) + | ((uint)g << 8) + | (uint)b; } /// /// Initializes a struct with the given RGB float value. /// /// - /// The following will create a color that has a value of + /// The following will create a color that has a value of /// #607c8c. /// /// Color darkGrey = new Color(0.38f, 0.49f, 0.55f); @@ -172,10 +183,9 @@ public Color(float r, float g, float b) throw new ArgumentOutOfRangeException(nameof(g), "Value must be within [0,1]."); if (b < 0.0f || b > 1.0f) throw new ArgumentOutOfRangeException(nameof(b), "Value must be within [0,1]."); - RawValue = - ((uint)(r * 255.0f) << 16) | - ((uint)(g * 255.0f) << 8) | - (uint)(b * 255.0f); + RawValue = ((uint)(r * 255.0f) << 16) + | ((uint)(g * 255.0f) << 8) + | (uint)(b * 255.0f); } public static bool operator ==(Color lhs, Color rhs) @@ -184,15 +194,22 @@ public Color(float r, float g, float b) public static bool operator !=(Color lhs, Color rhs) => lhs.RawValue != rhs.RawValue; + public static implicit operator Color(uint rawValue) + => new(rawValue); + + public static implicit operator uint(Color color) + => color.RawValue; + public override bool Equals(object obj) - => (obj is Color c && RawValue == c.RawValue); + => obj is Color c && RawValue == c.RawValue; public override int GetHashCode() => RawValue.GetHashCode(); - public static implicit operator StandardColor(Color color) => - StandardColor.FromArgb((int)color.RawValue); - public static explicit operator Color(StandardColor color) => - new Color((uint)color.ToArgb() << 8 >> 8); + public static implicit operator StandardColor(Color color) + => StandardColor.FromArgb((int)color.RawValue); + + public static explicit operator Color(StandardColor color) + => new((uint)color.ToArgb() << 8 >> 8); /// /// Gets the hexadecimal representation of the color (e.g. #000ccc). diff --git a/src/Discord.Net.Core/Entities/Roles/IRole.cs b/src/Discord.Net.Core/Entities/Roles/IRole.cs index c02322be9..59ca41e31 100644 --- a/src/Discord.Net.Core/Entities/Roles/IRole.cs +++ b/src/Discord.Net.Core/Entities/Roles/IRole.cs @@ -52,6 +52,20 @@ public interface IRole : ISnowflakeEntity, IDeletable, IMentionable, IComparable /// string Name { get; } /// + /// Gets the icon of this role. + /// + /// + /// A string containing the hash of this role's icon. + /// + string Icon { get; } + /// + /// Gets the unicode emoji of this role. + /// + /// + /// This field is mutually exclusive with , either icon is set or emoji is set. + /// + Emoji Emoji { get; } + /// /// Gets the permissions granted to members of this role. /// /// @@ -86,5 +100,13 @@ public interface IRole : ISnowflakeEntity, IDeletable, IMentionable, IComparable /// A task that represents the asynchronous modification operation. /// Task ModifyAsync(Action func, RequestOptions options = null); + + /// + /// Gets the image url of the icon role. + /// + /// + /// An image url of the icon role. + /// + string GetIconUrl(); } } diff --git a/src/Discord.Net.Core/Entities/Roles/RoleProperties.cs b/src/Discord.Net.Core/Entities/Roles/RoleProperties.cs index a58112b28..93cda8d5b 100644 --- a/src/Discord.Net.Core/Entities/Roles/RoleProperties.cs +++ b/src/Discord.Net.Core/Entities/Roles/RoleProperties.cs @@ -50,6 +50,11 @@ public class RoleProperties /// This value may not be set if the role is an @everyone role. /// public Optional Hoist { get; set; } + + /// + /// Gets or sets the icon of the role. + /// + public Optional Icon { get; set; } /// /// Gets or sets whether or not this role can be mentioned. /// diff --git a/src/Discord.Net.Core/Entities/Stickers/ICustomSticker.cs b/src/Discord.Net.Core/Entities/Stickers/ICustomSticker.cs new file mode 100644 index 000000000..9cba38c80 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Stickers/ICustomSticker.cs @@ -0,0 +1,59 @@ +using System; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents a custom sticker within a guild. + /// + public interface ICustomSticker : ISticker + { + /// + /// Gets the users id who uploaded the sticker. + /// + /// + /// In order to get the author id, the bot needs the MANAGE_EMOJIS_AND_STICKERS permission. + /// + ulong? AuthorId { get; } + + /// + /// Gets the guild that this custom sticker is in. + /// + IGuild Guild { get; } + + /// + /// Modifies this sticker. + /// + /// + /// This method modifies this sticker with the specified properties. To see an example of this + /// method and what properties are available, please refer to . + ///
+ ///
+ /// The bot needs the MANAGE_EMOJIS_AND_STICKERS permission within the guild in order to modify stickers. + ///
+ /// + /// The following example replaces the name of the sticker with kekw. + /// + /// await sticker.ModifyAsync(x => x.Name = "kekw"); + /// + /// + /// A delegate containing the properties to modify the sticker with. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous modification operation. + /// + Task ModifyAsync(Action func, RequestOptions options = null); + + /// + /// Deletes the current sticker. + /// + /// + /// The bot needs the MANAGE_EMOJIS_AND_STICKERS permission inside the guild in order to delete stickers. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous deletion operation. + /// + Task DeleteAsync(RequestOptions options = null); + } +} diff --git a/src/Discord.Net.Core/Entities/Messages/ISticker.cs b/src/Discord.Net.Core/Entities/Stickers/ISticker.cs similarity index 71% rename from src/Discord.Net.Core/Entities/Messages/ISticker.cs rename to src/Discord.Net.Core/Entities/Stickers/ISticker.cs index e7e4405b6..9deea753f 100644 --- a/src/Discord.Net.Core/Entities/Messages/ISticker.cs +++ b/src/Discord.Net.Core/Entities/Stickers/ISticker.cs @@ -5,7 +5,7 @@ namespace Discord /// /// Represents a discord sticker. /// - public interface ISticker + public interface ISticker : IStickerItem { /// /// Gets the ID of this sticker. @@ -13,7 +13,7 @@ public interface ISticker /// /// A snowflake ID associated with this sticker. /// - ulong Id { get; } + new ulong Id { get; } /// /// Gets the ID of the pack of this sticker. /// @@ -27,7 +27,7 @@ public interface ISticker /// /// A with the name of this sticker. /// - string Name { get; } + new string Name { get; } /// /// Gets the description of this sticker. /// @@ -43,25 +43,29 @@ public interface ISticker /// IReadOnlyCollection Tags { get; } /// - /// Gets the asset hash of this sticker. + /// Gets the type of this sticker. /// - /// - /// A with the asset hash of this sticker. - /// - string Asset { get; } - /// - /// Gets the preview asset hash of this sticker. - /// - /// - /// A with the preview asset hash of this sticker. - /// - string PreviewAsset { get; } + StickerType Type { get; } /// /// Gets the format type of this sticker. /// /// /// A with the format type of this sticker. /// - StickerFormatType FormatType { get; } + new StickerFormatType Format { get; } + + /// + /// Gets whether this guild sticker can be used, may be false due to loss of Server Boosts. + /// + bool? IsAvailable { get; } + + /// + /// Gets the standard sticker's sort order within its pack. + /// + int? SortOrder { get; } + /// + /// Gets the image url for this sticker. + /// + string GetStickerUrl(); } } diff --git a/src/Discord.Net.Core/Entities/Stickers/IStickerItem.cs b/src/Discord.Net.Core/Entities/Stickers/IStickerItem.cs new file mode 100644 index 000000000..07ea63db9 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Stickers/IStickerItem.cs @@ -0,0 +1,23 @@ +namespace Discord +{ + /// + /// Represents a partial sticker item received with a message. + /// + public interface IStickerItem + { + /// + /// The id of the sticker. + /// + ulong Id { get; } + + /// + /// The name of the sticker. + /// + string Name { get; } + + /// + /// The format of the sticker. + /// + StickerFormatType Format { get; } + } +} diff --git a/src/Discord.Net.Core/Entities/Stickers/StickerPack.cs b/src/Discord.Net.Core/Entities/Stickers/StickerPack.cs new file mode 100644 index 000000000..c0c90aa69 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Stickers/StickerPack.cs @@ -0,0 +1,59 @@ +using System.Collections.Generic; +using System.Collections.Immutable; + +namespace Discord +{ + /// + /// Represents a discord sticker pack. + /// + /// The type of the stickers within the collection. + public class StickerPack where TSticker : ISticker + { + /// + /// Gets the id of the sticker pack. + /// + public ulong Id { get; } + + /// + /// Gets a collection of the stickers in the pack. + /// + public IReadOnlyCollection Stickers { get; } + + /// + /// Gets the name of the sticker pack. + /// + public string Name { get; } + + /// + /// Gets the id of the pack's SKU. + /// + public ulong SkuId { get; } + + /// + /// Gets the id of a sticker in the pack which is shown as the pack's icon. + /// + public ulong? CoverStickerId { get; } + + /// + /// Gets the description of the sticker pack. + /// + public string Description { get; } + + /// + /// Gets the id of the sticker pack's banner image + /// + public ulong BannerAssetId { get; } + + internal StickerPack(string name, ulong id, ulong skuid, ulong? coverStickerId, string description, ulong bannerAssetId, IEnumerable stickers) + { + Name = name; + Id = id; + SkuId = skuid; + CoverStickerId = coverStickerId; + Description = description; + BannerAssetId = bannerAssetId; + + Stickers = stickers.ToImmutableArray(); + } + } +} diff --git a/src/Discord.Net.Core/Entities/Stickers/StickerProperties.cs b/src/Discord.Net.Core/Entities/Stickers/StickerProperties.cs new file mode 100644 index 000000000..5f51e5f3d --- /dev/null +++ b/src/Discord.Net.Core/Entities/Stickers/StickerProperties.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace Discord +{ + /// + /// Represents a class used to modify stickers. + /// + public class StickerProperties + { + /// + /// Gets or sets the name of the sticker. + /// + public Optional Name { get; set; } + + /// + /// Gets or sets the description of the sticker. + /// + public Optional Description { get; set; } + + /// + /// Gets or sets the tags of the sticker. + /// + public Optional> Tags { get; set; } + } +} diff --git a/src/Discord.Net.Core/Entities/Stickers/StickerType.cs b/src/Discord.Net.Core/Entities/Stickers/StickerType.cs new file mode 100644 index 000000000..0db550772 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Stickers/StickerType.cs @@ -0,0 +1,18 @@ +namespace Discord +{ + /// + /// Represents a type of sticker.. + /// + public enum StickerType + { + /// + /// Represents a discord standard sticker, this type of sticker cannot be modified by an application. + /// + Standard = 1, + + /// + /// Represents a sticker that was created within a guild. + /// + Guild = 2 + } +} diff --git a/src/Discord.Net.Core/Entities/Users/IGuildUser.cs b/src/Discord.Net.Core/Entities/Users/IGuildUser.cs index 492cb9566..947ff8521 100644 --- a/src/Discord.Net.Core/Entities/Users/IGuildUser.cs +++ b/src/Discord.Net.Core/Entities/Users/IGuildUser.cs @@ -25,6 +25,13 @@ public interface IGuildUser : IUser, IVoiceState /// string Nickname { get; } /// + /// Gets the guild specific avatar for this users. + /// + /// + /// The users guild avatar hash if they have one; otherwise . + /// + string GuildAvatarId { get; } + /// /// Gets the guild-level permissions for this user. /// /// @@ -73,13 +80,18 @@ public interface IGuildUser : IUser, IVoiceState /// bool? IsPending { get; } + /// + /// Gets the users position within the role hierarchy. + /// + int Hierarchy { get; } + /// /// Gets the level permissions granted to this user to a given channel. /// /// /// The following example checks if the current user has the ability to send a message with attachment in /// this channel; if so, uploads a file via . - /// + /// /// if (currentUser?.GetPermissions(targetChannel)?.AttachFiles) /// await targetChannel.SendFileAsync("fortnite.png"); /// @@ -91,6 +103,20 @@ public interface IGuildUser : IUser, IVoiceState /// ChannelPermissions GetPermissions(IGuildChannel channel); + /// + /// Gets the guild avatar URL for this user. + /// + /// + /// This property retrieves a URL for this guild user's guild specific avatar. In event that the user does not have a valid guild avatar + /// (i.e. their avatar identifier is not set), this method will return null. + /// + /// The format to return. + /// The size of the image to return in. This can be any power of two between 16 and 2048. + /// + /// + /// A string representing the user's avatar URL; null if the user does not have an avatar in place. + /// + string GetGuildAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128); /// /// Kicks this user from this guild. /// diff --git a/src/Discord.Net.Core/Entities/Users/IUser.cs b/src/Discord.Net.Core/Entities/Users/IUser.cs index 9596a8338..2f79450f3 100644 --- a/src/Discord.Net.Core/Entities/Users/IUser.cs +++ b/src/Discord.Net.Core/Entities/Users/IUser.cs @@ -10,19 +10,20 @@ public interface IUser : ISnowflakeEntity, IMentionable, IPresence /// /// Gets the identifier of this user's avatar. /// - string AvatarId { get; } + string AvatarId { get; } /// /// Gets the avatar URL for this user. /// /// /// This property retrieves a URL for this user's avatar. In event that the user does not have a valid avatar - /// (i.e. their avatar identifier is not set), this property will return null. If you wish to + /// (i.e. their avatar identifier is not set), this method will return null. If you wish to /// retrieve the default avatar for this user, consider using (see /// example). /// /// - /// The following example attempts to retrieve the user's current avatar and send it to a channel; if one is - /// not set, a default avatar for this user will be returned instead. + /// The following example attempts to retrieve the user's current avatar and send it to a channel; if one is + /// not set, a default avatar for this user will be returned instead. /// /// @@ -93,8 +94,8 @@ public interface IUser : ISnowflakeEntity, IMentionable, IPresence /// This method is used to obtain or create a channel used to send a direct message. /// /// In event that the current user cannot send a message to the target user, a channel can and will - /// still be created by Discord. However, attempting to send a message will yield a - /// with a 403 as its + /// still be created by Discord. However, attempting to send a message will yield a + /// with a 403 as its /// . There are currently no official workarounds by /// Discord. /// diff --git a/src/Discord.Net.Core/Entities/Users/IVoiceState.cs b/src/Discord.Net.Core/Entities/Users/IVoiceState.cs index a9b347003..c9a22761f 100644 --- a/src/Discord.Net.Core/Entities/Users/IVoiceState.cs +++ b/src/Discord.Net.Core/Entities/Users/IVoiceState.cs @@ -1,3 +1,5 @@ +using System; + namespace Discord { /// @@ -62,5 +64,9 @@ public interface IVoiceState /// true if the user is streaming; otherwise false. /// bool IsStreaming { get; } + /// + /// Gets the time on which the user requested to speak. + /// + DateTimeOffset? RequestToSpeakTimestamp { get; } } } diff --git a/src/Discord.Net.Core/Entities/Users/UserProperties.cs b/src/Discord.Net.Core/Entities/Users/UserProperties.cs index 68232b254..4cf4162a9 100644 --- a/src/Discord.Net.Core/Entities/Users/UserProperties.cs +++ b/src/Discord.Net.Core/Entities/Users/UserProperties.cs @@ -61,9 +61,13 @@ public enum UserProperties /// Flag given to users that developed bots and early verified their accounts. /// EarlyVerifiedBotDeveloper = 1 << 17, - /// + /// /// Flag given to users that are discord certified moderators who has give discord's exam. /// DiscordCertifiedModerator = 1 << 18, + /// + /// Flag given to bots that use only outgoing webhooks, exclusively. + /// + BotHTTPInteractions = 1 << 19, } } diff --git a/src/Discord.Net.Core/Entities/Webhooks/IWebhook.cs b/src/Discord.Net.Core/Entities/Webhooks/IWebhook.cs index b2d017316..d5bc70d71 100644 --- a/src/Discord.Net.Core/Entities/Webhooks/IWebhook.cs +++ b/src/Discord.Net.Core/Entities/Webhooks/IWebhook.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading.Tasks; namespace Discord @@ -49,6 +49,11 @@ public interface IWebhook : IDeletable, ISnowflakeEntity /// IUser Creator { get; } + /// + /// Gets the ID of the application owning this webhook. + /// + ulong? ApplicationId { get; } + /// /// Modifies this webhook. /// diff --git a/src/Discord.Net.Core/Extensions/GuildExtensions.cs b/src/Discord.Net.Core/Extensions/GuildExtensions.cs index 58b749cc4..9dd8de82e 100644 --- a/src/Discord.Net.Core/Extensions/GuildExtensions.cs +++ b/src/Discord.Net.Core/Extensions/GuildExtensions.cs @@ -20,5 +20,21 @@ public static bool GetWelcomeMessagesEnabled(this IGuild guild) /// A bool indicating if the guild boost messages are enabled in the system channel. public static bool GetGuildBoostMessagesEnabled(this IGuild guild) => !guild.SystemChannelFlags.HasFlag(SystemChannelMessageDeny.GuildBoost); + + /// + /// Gets if guild setup system messages are enabled. + /// + /// The guild to check. + /// A bool indicating if the guild setup messages are enabled in the system channel. + public static bool GetGuildSetupTipMessagesEnabled(this IGuild guild) + => !guild.SystemChannelFlags.HasFlag(SystemChannelMessageDeny.GuildSetupTip); + + /// + /// Gets if guild welcome messages have a reply with sticker button. + /// + /// The guild to check. + /// A bool indicating if the guild welcome messages have a reply with sticker button. + public static bool GetGuildWelcomeMessageReplyEnabled(this IGuild guild) + => !guild.SystemChannelFlags.HasFlag(SystemChannelMessageDeny.WelcomeMessageReply); } } diff --git a/src/Discord.Net.Core/Extensions/MessageExtensions.cs b/src/Discord.Net.Core/Extensions/MessageExtensions.cs index b043d7b77..c187ecd5b 100644 --- a/src/Discord.Net.Core/Extensions/MessageExtensions.cs +++ b/src/Discord.Net.Core/Extensions/MessageExtensions.cs @@ -24,7 +24,7 @@ public static string GetJumpUrl(this IMessage msg) /// Add multiple reactions to a message. ///
/// - /// This method does not bulk add reactions! It will send a request for each reaction inculded. + /// This method does not bulk add reactions! It will send a request for each reaction included. /// /// /// @@ -34,7 +34,7 @@ public static string GetJumpUrl(this IMessage msg) /// /// /// The message to add reactions to. - /// An array of reactions to add to the message + /// An array of reactions to add to the message. /// The options to be used when sending the request. /// /// A task that represents the asynchronous operation for adding a reaction to this message. @@ -59,7 +59,8 @@ public static async Task AddReactionsAsync(this IUserMessage msg, IEmote[] react /// ///
/// The message to remove reactions from. - /// An array of reactions to remove from the message + /// The user who removed the reaction. + /// An array of reactions to remove from the message. /// The options to be used when sending the request. /// /// A task that represents the asynchronous operation for removing a reaction to this message. @@ -75,21 +76,25 @@ public static async Task RemoveReactionsAsync(this IUserMessage msg, IUser user, /// /// Sends an inline reply that references a message. /// + /// The message that is being replied on. /// The message to be sent. /// Determines whether the message should be read aloud by Discord or not. /// The to be sent. + /// A array of s to send with this response. Max 10. /// /// Specifies if notifications are sent for mentioned users and roles in the message . /// If null, all mentioned roles and users will be notified. /// /// The options to be used when sending the request. + /// The message components to be included with this message. Used for interactions. + /// A collection of stickers to send with the message. /// /// A task that represents an asynchronous send operation for delivering the message. The task result /// contains the sent message. /// - public static async Task ReplyAsync(this IUserMessage msg, string text = null, bool isTTS = false, Embed embed = null, AllowedMentions allowedMentions = null, RequestOptions options = null) + public static async Task ReplyAsync(this IUserMessage msg, string text = null, bool isTTS = false, Embed embed = null, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent components = null, ISticker[] stickers = null, Embed[] embeds = null) { - return await msg.Channel.SendMessageAsync(text, isTTS, embed, options, allowedMentions, new MessageReference(messageId: msg.Id)).ConfigureAwait(false); + return await msg.Channel.SendMessageAsync(text, isTTS, embed, options, allowedMentions, new MessageReference(messageId: msg.Id), components, stickers, embeds).ConfigureAwait(false); } } } diff --git a/src/Discord.Net.Core/Extensions/ObjectExtensions.cs b/src/Discord.Net.Core/Extensions/ObjectExtensions.cs new file mode 100644 index 000000000..240fb47aa --- /dev/null +++ b/src/Discord.Net.Core/Extensions/ObjectExtensions.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + internal static class ObjectExtensions + { + public static bool IsNumericType(this object o) + { + switch (Type.GetTypeCode(o.GetType())) + { + case TypeCode.Byte: + case TypeCode.SByte: + case TypeCode.UInt16: + case TypeCode.UInt32: + case TypeCode.UInt64: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.Decimal: + case TypeCode.Double: + case TypeCode.Single: + return true; + default: + return false; + } + } + } +} diff --git a/src/Discord.Net.Core/Extensions/UserExtensions.cs b/src/Discord.Net.Core/Extensions/UserExtensions.cs index 3e46308e6..e268eae84 100644 --- a/src/Discord.Net.Core/Extensions/UserExtensions.cs +++ b/src/Discord.Net.Core/Extensions/UserExtensions.cs @@ -32,6 +32,8 @@ public static class UserExtensions /// Specifies if notifications are sent for mentioned users and roles in the message . /// If null, all mentioned roles and users will be notified. /// + /// The message components to be included with this message. Used for interactions. + /// A array of s to send with this response. Max 10. /// /// A task that represents the asynchronous send operation. The task result contains the sent message. /// @@ -40,9 +42,11 @@ public static async Task SendMessageAsync(this IUser user, bool isTTS = false, Embed embed = null, RequestOptions options = null, - AllowedMentions allowedMentions = null) + AllowedMentions allowedMentions = null, + MessageComponent component = null, + Embed[] embeds = null) { - return await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendMessageAsync(text, isTTS, embed, options, allowedMentions).ConfigureAwait(false); + return await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendMessageAsync(text, isTTS, embed, options, allowedMentions, component: component, embeds: embeds).ConfigureAwait(false); } /// @@ -81,6 +85,8 @@ public static async Task SendMessageAsync(this IUser user, /// Whether the message should be read aloud by Discord or not. /// The to be sent. /// The options to be used when sending the request. + /// The message component to be included with this message. Used for interactions. + /// A array of s to send with this response. Max 10. /// /// A task that represents an asynchronous send operation for delivering the message. The task result /// contains the sent message. @@ -91,10 +97,11 @@ public static async Task SendFileAsync(this IUser user, string text = null, bool isTTS = false, Embed embed = null, - RequestOptions options = null - ) + RequestOptions options = null, + MessageComponent component = null, + Embed[] embeds = null) { - return await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(stream, filename, text, isTTS, embed, options).ConfigureAwait(false); + return await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(stream, filename, text, isTTS, embed, options, component: component, embeds: embeds).ConfigureAwait(false); } /// @@ -138,6 +145,8 @@ public static async Task SendFileAsync(this IUser user, /// Whether the message should be read aloud by Discord or not. /// The to be sent. /// The options to be used when sending the request. + /// The message component to be included with this message. Used for interactions. + /// A array of s to send with this response. Max 10. /// /// A task that represents an asynchronous send operation for delivering the message. The task result /// contains the sent message. @@ -147,9 +156,11 @@ public static async Task SendFileAsync(this IUser user, string text = null, bool isTTS = false, Embed embed = null, - RequestOptions options = null) + RequestOptions options = null, + MessageComponent component = null, + Embed[] embeds = null) { - return await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(filePath, text, isTTS, embed, options).ConfigureAwait(false); + return await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(filePath, text, isTTS, embed, options, component: component, embeds: embeds).ConfigureAwait(false); } /// diff --git a/src/Discord.Net.Core/Format.cs b/src/Discord.Net.Core/Format.cs index 0ab70f89c..63f9d15a6 100644 --- a/src/Discord.Net.Core/Format.cs +++ b/src/Discord.Net.Core/Format.cs @@ -1,4 +1,5 @@ using System.Text; +using System.Text.RegularExpressions; namespace Discord { @@ -14,7 +15,7 @@ public static class Format public static string Italics(string text) => $"*{text}*"; /// Returns a markdown-formatted string with underline formatting. public static string Underline(string text) => $"__{text}__"; - /// Returns a markdown-formatted string with strikethrough formatting. + /// Returns a markdown-formatted string with strike-through formatting. public static string Strikethrough(string text) => $"~~{text}~~"; /// Returns a string with spoiler formatting. public static string Spoiler(string text) => $"||{text}||"; @@ -91,5 +92,17 @@ public static string BlockQuote(string text) return $">>> {text}"; } + + /// + /// Remove discord supported markdown from text. + /// + /// The to remove markdown from. + /// Gets the unformatted text. + public static string StripMarkDown(string text) + { + //Remove discord supported markdown + var newText = Regex.Replace(text, @"(\*|_|`|~|>|\\)", ""); + return newText; + } } } diff --git a/src/Discord.Net.Core/GatewayIntents.cs b/src/Discord.Net.Core/GatewayIntents.cs index 6976806b2..f2a99e44c 100644 --- a/src/Discord.Net.Core/GatewayIntents.cs +++ b/src/Discord.Net.Core/GatewayIntents.cs @@ -39,13 +39,15 @@ public enum GatewayIntents DirectMessageReactions = 1 << 13, /// This intent includes TYPING_START DirectMessageTyping = 1 << 14, + /// This intent includes GUILD_SCHEDULED_EVENT_CREATE, GUILD_SCHEDULED_EVENT_UPDATE, GUILD_SCHEDULED_EVENT_DELETE, GUILD_SCHEDULED_EVENT_USER_ADD, GUILD_SCHEDULED_EVENT_USER_REMOVE + GuildScheduledEvents = 1 << 16, /// - /// This intent includes all but and - /// that are privileged must be enabled for the application. + /// This intent includes all but and + /// which are privileged and must be enabled in the Developer Portal. /// AllUnprivileged = Guilds | GuildBans | GuildEmojis | GuildIntegrations | GuildWebhooks | GuildInvites | GuildVoiceStates | GuildMessages | GuildMessageReactions | GuildMessageTyping | DirectMessages | - DirectMessageReactions | DirectMessageTyping, + DirectMessageReactions | DirectMessageTyping | GuildScheduledEvents, /// /// This intent includes all of them, including privileged ones. /// diff --git a/src/Discord.Net.Core/IDiscordClient.cs b/src/Discord.Net.Core/IDiscordClient.cs index d7d6d2856..f6981d552 100644 --- a/src/Discord.Net.Core/IDiscordClient.cs +++ b/src/Discord.Net.Core/IDiscordClient.cs @@ -141,6 +141,47 @@ public interface IDiscordClient : IDisposable /// Task> GetConnectionsAsync(RequestOptions options = null); + /// + /// Gets a global application command. + /// + /// The id of the command. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains the application command if found, otherwise + /// . + /// + Task GetGlobalApplicationCommandAsync(ulong id, RequestOptions options = null); + + /// + /// Gets a collection of all global commands. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection of global + /// application commands. + /// + Task> GetGlobalApplicationCommandsAsync(RequestOptions options = null); + + /// + /// Creates a global application command. + /// + /// The properties to use when creating the command. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the created application command. + /// + Task CreateGlobalApplicationCommand(ApplicationCommandProperties properties, RequestOptions options = null); + + /// + /// Bulk overwrites all global application commands. + /// + /// A collection of properties to use when creating the commands. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains a collection of application commands that were created. + /// + Task> BulkOverwriteGlobalApplicationCommand(ApplicationCommandProperties[] properties, RequestOptions options = null); + /// /// Gets a guild. /// diff --git a/src/Discord.Net.Core/Net/ApplicationCommandException.cs b/src/Discord.Net.Core/Net/ApplicationCommandException.cs new file mode 100644 index 000000000..4b4890d12 --- /dev/null +++ b/src/Discord.Net.Core/Net/ApplicationCommandException.cs @@ -0,0 +1,15 @@ +using System; +using System.Linq; + +namespace Discord.Net +{ + [Obsolete("Please use HttpException instead of this. Will be removed in next major version.", false)] + public class ApplicationCommandException : HttpException + { + public ApplicationCommandException(HttpException httpError) + : base(httpError.HttpCode, httpError.Request, httpError.DiscordCode, httpError.Reason, httpError.Errors.ToArray()) + { + + } + } +} diff --git a/src/Discord.Net.Core/Net/HttpException.cs b/src/Discord.Net.Core/Net/HttpException.cs index ff9cf91f2..07551f0e7 100644 --- a/src/Discord.Net.Core/Net/HttpException.cs +++ b/src/Discord.Net.Core/Net/HttpException.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Collections.Immutable; using System.Net; namespace Discord.Net @@ -25,7 +27,7 @@ public class HttpException : Exception /// JSON error code /// from Discord, or null if none. /// - public int? DiscordCode { get; } + public DiscordErrorCode? DiscordCode { get; } /// /// Gets the reason of the exception. /// @@ -34,6 +36,10 @@ public class HttpException : Exception /// Gets the request object used to send the request. /// public IRequest Request { get; } + /// + /// Gets a collection of json errors describing what went wrong with the request. + /// + public IReadOnlyCollection Errors { get; } /// /// Initializes a new instance of the class. @@ -42,13 +48,14 @@ public class HttpException : Exception /// The request that was sent prior to the exception. /// The Discord status code returned. /// The reason behind the exception. - public HttpException(HttpStatusCode httpCode, IRequest request, int? discordCode = null, string reason = null) - : base(CreateMessage(httpCode, discordCode, reason)) + public HttpException(HttpStatusCode httpCode, IRequest request, DiscordErrorCode? discordCode = null, string reason = null, DiscordJsonError[] errors = null) + : base(CreateMessage(httpCode, (int?)discordCode, reason)) { HttpCode = httpCode; Request = request; DiscordCode = discordCode; Reason = reason; + Errors = errors?.ToImmutableArray() ?? ImmutableArray.Empty; } private static string CreateMessage(HttpStatusCode httpCode, int? discordCode = null, string reason = null) diff --git a/src/Discord.Net.Core/Net/Rest/IRateLimitInfo.cs b/src/Discord.Net.Core/Net/Rest/IRateLimitInfo.cs new file mode 100644 index 000000000..816f25af4 --- /dev/null +++ b/src/Discord.Net.Core/Net/Rest/IRateLimitInfo.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + /// + /// Represents a generic ratelimit info. + /// + public interface IRateLimitInfo + { + /// + /// Gets whether or not this ratelimit info is global. + /// + bool IsGlobal { get; } + + /// + /// Gets the number of requests that can be made. + /// + int? Limit { get; } + + /// + /// Gets the number of remaining requests that can be made. + /// + int? Remaining { get; } + + /// + /// Gets the total time (in seconds) of when the current rate limit bucket will reset. Can have decimals to match previous millisecond ratelimit precision. + /// + int? RetryAfter { get; } + + /// + /// Gets the at which the rate limit resets. + /// + DateTimeOffset? Reset { get; } + + /// + /// Gets the absolute time when this ratelimit resets. + /// + TimeSpan? ResetAfter { get; } + + /// + /// Gets a unique string denoting the rate limit being encountered (non-inclusive of major parameters in the route path). + /// + string Bucket { get; } + + /// + /// Gets the amount of lag for the request. This is used to denote the precise time of when the ratelimit expires. + /// + TimeSpan? Lag { get; } + + /// + /// Gets the endpoint that this ratelimit info came from. + /// + string Endpoint { get; } + } +} diff --git a/src/Discord.Net.Core/RequestOptions.cs b/src/Discord.Net.Core/RequestOptions.cs index dbb240273..46aa2681f 100644 --- a/src/Discord.Net.Core/RequestOptions.cs +++ b/src/Discord.Net.Core/RequestOptions.cs @@ -1,5 +1,7 @@ using Discord.Net; +using System; using System.Threading; +using System.Threading.Tasks; namespace Discord { @@ -14,10 +16,10 @@ public class RequestOptions public static RequestOptions Default => new RequestOptions(); /// - /// Gets or sets the maximum time to wait for for this request to complete. + /// Gets or sets the maximum time to wait for this request to complete. /// /// - /// Gets or set the max time, in milliseconds, to wait for for this request to complete. If + /// Gets or set the max time, in milliseconds, to wait for this request to complete. If /// null, a request will not time out. If a rate limit has been triggered for this request's bucket /// and will not be unpaused in time, this request will fail immediately. /// @@ -57,6 +59,11 @@ public class RequestOptions /// public bool? UseSystemClock { get; set; } + /// + /// Gets or sets the callback to execute regarding ratelimits for this request. + /// + public Func RatelimitCallback { get; set; } + internal bool IgnoreState { get; set; } internal BucketId BucketId { get; set; } internal bool IsClientBucket { get; set; } @@ -71,6 +78,17 @@ internal static RequestOptions CreateOrClone(RequestOptions options) return options.Clone(); } + internal void ExecuteRatelimitCallback(IRateLimitInfo info) + { + if (RatelimitCallback != null) + { + _ = Task.Run(async () => + { + await RatelimitCallback(info); + }); + } + } + /// /// Initializes a new class with the default request timeout set in /// . diff --git a/src/Discord.Net.Core/Utils/Cacheable.cs b/src/Discord.Net.Core/Utils/Cacheable.cs index 1857ae7a0..4aa768292 100644 --- a/src/Discord.Net.Core/Utils/Cacheable.cs +++ b/src/Discord.Net.Core/Utils/Cacheable.cs @@ -63,4 +63,60 @@ public async Task DownloadAsync() /// public async Task GetOrDownloadAsync() => HasValue ? Value : await DownloadAsync().ConfigureAwait(false); } + public struct Cacheable + where TCachedEntity : IEntity, TRelationship + where TDownloadableEntity : IEntity, TRelationship + where TId : IEquatable + { + /// + /// Gets whether this entity is cached. + /// + public bool HasValue { get; } + /// + /// Gets the ID of this entity. + /// + public TId Id { get; } + /// + /// Gets the entity if it could be pulled from cache. + /// + /// + /// This value is not guaranteed to be set; in cases where the entity cannot be pulled from cache, it is + /// null. + /// + public TCachedEntity Value { get; } + private Func> DownloadFunc { get; } + + internal Cacheable(TCachedEntity value, TId id, bool hasValue, Func> downloadFunc) + { + Value = value; + Id = id; + HasValue = hasValue; + DownloadFunc = downloadFunc; + } + + /// + /// Downloads this entity. + /// + /// Thrown when used from a user account. + /// Thrown when the message is deleted. + /// + /// A task that represents the asynchronous download operation. The task result contains the downloaded + /// entity. + /// + public async Task DownloadAsync() + { + return await DownloadFunc().ConfigureAwait(false); + } + + /// + /// Returns the cached entity if it exists; otherwise downloads it. + /// + /// Thrown when used from a user account. + /// Thrown when the message is deleted and is not in cache. + /// + /// A task that represents the asynchronous operation that attempts to get the message via cache or to + /// download the message. The task result contains the downloaded entity. + /// + public async Task GetOrDownloadAsync() => HasValue ? Value : await DownloadAsync().ConfigureAwait(false); + } } diff --git a/src/Discord.Net.Core/Utils/MentionUtils.cs b/src/Discord.Net.Core/Utils/MentionUtils.cs index 6ffb7eee6..059df6b5a 100644 --- a/src/Discord.Net.Core/Utils/MentionUtils.cs +++ b/src/Discord.Net.Core/Utils/MentionUtils.cs @@ -40,6 +40,7 @@ public static class MentionUtils /// /// Parses a provided user mention string. /// + /// The user mention. /// Invalid mention format. public static ulong ParseUser(string text) { @@ -50,6 +51,8 @@ public static ulong ParseUser(string text) /// /// Tries to parse a provided user mention string. /// + /// The user mention. + /// The UserId of the user. public static bool TryParseUser(string text, out ulong userId) { if (text.Length >= 3 && text[0] == '<' && text[1] == '@' && text[text.Length - 1] == '>') diff --git a/src/Discord.Net.Core/Utils/Optional.cs b/src/Discord.Net.Core/Utils/Optional.cs index 348179699..985be9240 100644 --- a/src/Discord.Net.Core/Utils/Optional.cs +++ b/src/Discord.Net.Core/Utils/Optional.cs @@ -7,7 +7,7 @@ namespace Discord [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public struct Optional { - public static Optional Unspecified => default(Optional); + public static Optional Unspecified => default; private readonly T _value; /// Gets the value for this parameter. @@ -43,18 +43,18 @@ public override bool Equals(object other) public override int GetHashCode() => IsSpecified ? _value.GetHashCode() : 0; public override string ToString() => IsSpecified ? _value?.ToString() : null; - private string DebuggerDisplay => IsSpecified ? (_value?.ToString() ?? "") : ""; + private string DebuggerDisplay => IsSpecified ? _value?.ToString() ?? "" : ""; - public static implicit operator Optional(T value) => new Optional(value); + public static implicit operator Optional(T value) => new(value); public static explicit operator T(Optional value) => value.Value; } public static class Optional { public static Optional Create() => Optional.Unspecified; - public static Optional Create(T value) => new Optional(value); + public static Optional Create(T value) => new(value); public static T? ToNullable(this Optional val) where T : struct - => val.IsSpecified ? val.Value : (T?)null; + => val.IsSpecified ? val.Value : null; } } diff --git a/src/Discord.Net.Core/Utils/Preconditions.cs b/src/Discord.Net.Core/Utils/Preconditions.cs index 60415852c..ff8eb7c0d 100644 --- a/src/Discord.Net.Core/Utils/Preconditions.cs +++ b/src/Discord.Net.Core/Utils/Preconditions.cs @@ -4,7 +4,7 @@ namespace Discord { internal static class Preconditions { - //Objects + #region Objects /// must not be . public static void NotNull(T obj, string name, string msg = null) where T : class { if (obj == null) throw CreateNotNullException(name, msg); } /// must not be . @@ -15,8 +15,9 @@ private static ArgumentNullException CreateNotNullException(string name, string if (msg == null) return new ArgumentNullException(paramName: name); else return new ArgumentNullException(paramName: name, message: msg); } + #endregion - //Strings + #region Strings /// cannot be blank. public static void NotEmpty(string obj, string name, string msg = null) { if (obj.Length == 0) throw CreateNotEmptyException(name, msg); } /// cannot be blank. @@ -58,8 +59,9 @@ public static void NotNullOrWhitespace(Optional obj, string name, string private static ArgumentException CreateNotEmptyException(string name, string msg) => new ArgumentException(message: msg ?? "Argument cannot be blank.", paramName: name); + #endregion - //Numerics + #region Numerics /// Value may not be equal to . public static void NotEqual(sbyte obj, sbyte value, string name, string msg = null) { if (obj == value) throw CreateNotEqualException(name, msg, value); } /// Value may not be equal to . @@ -271,8 +273,9 @@ private static ArgumentException CreateAtMostException(string name, string ms private static ArgumentException CreateLessThanException(string name, string msg, T value) => new ArgumentException(message: msg ?? $"Value must be less than {value}.", paramName: name); + #endregion - // Bulk Delete + #region Bulk Delete /// Messages are younger than 2 weeks. public static void YoungerThanTwoWeeks(ulong[] collection, string name) { @@ -293,5 +296,6 @@ public static void NotEveryoneRole(ulong[] roles, ulong guildId, string name) throw new ArgumentException(message: "The everyone role cannot be assigned to a user.", paramName: name); } } + #endregion } } diff --git a/src/Discord.Net.Core/Utils/UrlValidation.cs b/src/Discord.Net.Core/Utils/UrlValidation.cs new file mode 100644 index 000000000..8e877bd4e --- /dev/null +++ b/src/Discord.Net.Core/Utils/UrlValidation.cs @@ -0,0 +1,42 @@ +using System; + +namespace Discord.Utils +{ + internal static class UrlValidation + { + /// + /// Not full URL validation right now. Just ensures protocol is present and that it's either http or https + /// should be used for url buttons. + /// + /// The URL to validate before sending to Discord. + /// to allow the attachment:// protocol; otherwise . + /// A URL must include a protocol (http or https). + /// true if URL is valid by our standard, false if null, throws an error upon invalid. + public static bool Validate(string url, bool allowAttachments = false) + { + if (string.IsNullOrEmpty(url)) + return false; + if (!(url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || url.StartsWith("https://", StringComparison.OrdinalIgnoreCase) || (allowAttachments ? url.StartsWith("attachment://", StringComparison.Ordinal) : false))) + throw new InvalidOperationException($"The url {url} must include a protocol (either {(allowAttachments ? "HTTP, HTTPS, or ATTACHMENT" : "HTTP or HTTPS")})"); + return true; + } + + /// + /// Not full URL validation right now. Just Ensures the protocol is either http, https, or discord + /// should be used everything other than url buttons. + /// + /// The URL to validate before sending to discord. + /// A URL must include a protocol (either http, https, or discord). + /// true if the URL is valid by our standard, false if null, throws an error upon invalid. + public static bool ValidateButton(string url) + { + if (string.IsNullOrEmpty(url)) + return false; + if (!(url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || + url.StartsWith("https://", StringComparison.OrdinalIgnoreCase) || + url.StartsWith("discord://", StringComparison.OrdinalIgnoreCase))) + throw new InvalidOperationException($"The url {url} must include a protocol (either HTTP, HTTPS, or DISCORD)"); + return true; + } + } +} diff --git a/src/Discord.Net.Examples/Core/Entities/Channels/IMessageChannel.Examples.cs b/src/Discord.Net.Examples/Core/Entities/Channels/IMessageChannel.Examples.cs index 5f9d4b5d6..d920e9710 100644 --- a/src/Discord.Net.Examples/Core/Entities/Channels/IMessageChannel.Examples.cs +++ b/src/Discord.Net.Examples/Core/Entities/Channels/IMessageChannel.Examples.cs @@ -108,7 +108,6 @@ await channel.SendFileAsync(b1nzyStream, "b1nzy.jpg", using (channel.EnterTypingState()) await LongRunningAsync(); #endregion - } } } diff --git a/src/Discord.Net.Examples/Discord.Net.Examples.csproj b/src/Discord.Net.Examples/Discord.Net.Examples.csproj index ec0253428..3371432b8 100644 --- a/src/Discord.Net.Examples/Discord.Net.Examples.csproj +++ b/src/Discord.Net.Examples/Discord.Net.Examples.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Discord.Net.Rest/API/Common/ActionRowComponent.cs b/src/Discord.Net.Rest/API/Common/ActionRowComponent.cs new file mode 100644 index 000000000..9dede7e03 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/ActionRowComponent.cs @@ -0,0 +1,32 @@ +using Newtonsoft.Json; +using System.Linq; + +namespace Discord.API +{ + internal class ActionRowComponent : IMessageComponent + { + [JsonProperty("type")] + public ComponentType Type { get; set; } + + [JsonProperty("components")] + public IMessageComponent[] Components { get; set; } + + internal ActionRowComponent() { } + internal ActionRowComponent(Discord.ActionRowComponent c) + { + Type = c.Type; + Components = c.Components?.Select(x => + { + return x.Type switch + { + ComponentType.Button => new ButtonComponent(x as Discord.ButtonComponent), + ComponentType.SelectMenu => new SelectMenuComponent(x as Discord.SelectMenuComponent), + _ => null + }; + }).ToArray(); + } + + [JsonIgnore] + string IMessageComponent.CustomId => null; + } +} diff --git a/src/Discord.Net.Rest/API/Common/Application.cs b/src/Discord.Net.Rest/API/Common/Application.cs index aba3e524b..4ef6940a2 100644 --- a/src/Discord.Net.Rest/API/Common/Application.cs +++ b/src/Discord.Net.Rest/API/Common/Application.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API @@ -8,7 +7,7 @@ internal class Application [JsonProperty("description")] public string Description { get; set; } [JsonProperty("rpc_origins")] - public string[] RPCOrigins { get; set; } + public Optional RPCOrigins { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("id")] @@ -19,12 +18,16 @@ internal class Application public bool IsBotPublic { get; set; } [JsonProperty("bot_require_code_grant")] public bool BotRequiresCodeGrant { get; set; } + [JsonProperty("install_params")] + public Optional InstallParams { get; set; } + [JsonProperty("team")] public Team Team { get; set; } [JsonProperty("flags"), Int53] - public Optional Flags { get; set; } + public Optional Flags { get; set; } [JsonProperty("owner")] public Optional Owner { get; set; } + public Optional Tags { get; set; } } } diff --git a/src/Discord.Net.Rest/API/Common/ApplicationCommand.cs b/src/Discord.Net.Rest/API/Common/ApplicationCommand.cs new file mode 100644 index 000000000..81598b96e --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/ApplicationCommand.cs @@ -0,0 +1,28 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class ApplicationCommand + { + [JsonProperty("id")] + public ulong Id { get; set; } + + [JsonProperty("type")] + public ApplicationCommandType Type { get; set; } = ApplicationCommandType.Slash; // defaults to 1 which is slash. + + [JsonProperty("application_id")] + public ulong ApplicationId { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + [JsonProperty("options")] + public Optional Options { get; set; } + + [JsonProperty("default_permission")] + public Optional DefaultPermissions { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionData.cs b/src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionData.cs new file mode 100644 index 000000000..a98ed77d6 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionData.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class ApplicationCommandInteractionData : IResolvable, IDiscordInteractionData + { + [JsonProperty("id")] + public ulong Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("options")] + public Optional Options { get; set; } + + [JsonProperty("resolved")] + public Optional Resolved { get; set; } + + [JsonProperty("type")] + public ApplicationCommandType Type { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionDataOption.cs b/src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionDataOption.cs new file mode 100644 index 000000000..1e488c4e6 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionDataOption.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class ApplicationCommandInteractionDataOption + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("type")] + public ApplicationCommandOptionType Type { get; set; } + + [JsonProperty("value")] + public Optional Value { get; set; } + + [JsonProperty("options")] + public Optional Options { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionDataResolved.cs b/src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionDataResolved.cs new file mode 100644 index 000000000..5b4b83e23 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/ApplicationCommandInteractionDataResolved.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; +using System.Collections.Generic; + +namespace Discord.API +{ + internal class ApplicationCommandInteractionDataResolved + { + [JsonProperty("users")] + public Optional> Users { get; set; } + + [JsonProperty("members")] + public Optional> Members { get; set; } + + [JsonProperty("channels")] + public Optional> Channels { get; set; } + + [JsonProperty("roles")] + public Optional> Roles { get; set; } + [JsonProperty("messages")] + public Optional> Messages { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/ApplicationCommandOption.cs b/src/Discord.Net.Rest/API/Common/ApplicationCommandOption.cs new file mode 100644 index 000000000..1207df282 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/ApplicationCommandOption.cs @@ -0,0 +1,88 @@ +using Newtonsoft.Json; +using System.Linq; + +namespace Discord.API +{ + internal class ApplicationCommandOption + { + [JsonProperty("type")] + public ApplicationCommandOptionType Type { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + [JsonProperty("default")] + public Optional Default { get; set; } + + [JsonProperty("required")] + public Optional Required { get; set; } + + [JsonProperty("choices")] + public Optional Choices { get; set; } + + [JsonProperty("options")] + public Optional Options { get; set; } + + [JsonProperty("autocomplete")] + public Optional Autocomplete { get; set; } + + [JsonProperty("min_value")] + public Optional MinValue { get; set; } + + [JsonProperty("max_value")] + public Optional MaxValue { get; set; } + + [JsonProperty("channel_types")] + public Optional ChannelTypes { get; set; } + + public ApplicationCommandOption() { } + + public ApplicationCommandOption(IApplicationCommandOption cmd) + { + Choices = cmd.Choices.Select(x => new ApplicationCommandOptionChoice + { + Name = x.Name, + Value = x.Value + }).ToArray(); + + Options = cmd.Options.Select(x => new ApplicationCommandOption(x)).ToArray(); + + ChannelTypes = cmd.ChannelTypes.ToArray(); + + Required = cmd.IsRequired ?? Optional.Unspecified; + Default = cmd.IsDefault ?? Optional.Unspecified; + MinValue = cmd.MinValue ?? Optional.Unspecified; + MaxValue = cmd.MaxValue ?? Optional.Unspecified; + + Name = cmd.Name; + Type = cmd.Type; + Description = cmd.Description; + } + public ApplicationCommandOption(ApplicationCommandOptionProperties option) + { + Choices = option.Choices?.Select(x => new ApplicationCommandOptionChoice + { + Name = x.Name, + Value = x.Value + }).ToArray() ?? Optional.Unspecified; + + Options = option.Options?.Select(x => new ApplicationCommandOption(x)).ToArray() ?? Optional.Unspecified; + + Required = option.IsRequired ?? Optional.Unspecified; + + Default = option.IsDefault ?? Optional.Unspecified; + MinValue = option.MinValue ?? Optional.Unspecified; + MaxValue = option.MaxValue ?? Optional.Unspecified; + + ChannelTypes = option.ChannelTypes?.ToArray() ?? Optional.Unspecified; + + Name = option.Name; + Type = option.Type; + Description = option.Description; + Autocomplete = option.IsAutocomplete; + } + } +} diff --git a/src/Discord.Net.Rest/API/Common/ApplicationCommandOptionChoice.cs b/src/Discord.Net.Rest/API/Common/ApplicationCommandOptionChoice.cs new file mode 100644 index 000000000..6f84437f6 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/ApplicationCommandOptionChoice.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class ApplicationCommandOptionChoice + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("value")] + public object Value { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/ApplicationCommandPermissions.cs b/src/Discord.Net.Rest/API/Common/ApplicationCommandPermissions.cs new file mode 100644 index 000000000..8bde80f50 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/ApplicationCommandPermissions.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class ApplicationCommandPermissions + { + [JsonProperty("id")] + public ulong Id { get; set; } + + [JsonProperty("type")] + public ApplicationCommandPermissionTarget Type { get; set; } + + [JsonProperty("permission")] + public bool Permission { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/Attachment.cs b/src/Discord.Net.Rest/API/Common/Attachment.cs index 4a651d9fa..7970dc9a5 100644 --- a/src/Discord.Net.Rest/API/Common/Attachment.cs +++ b/src/Discord.Net.Rest/API/Common/Attachment.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API @@ -9,6 +8,10 @@ internal class Attachment public ulong Id { get; set; } [JsonProperty("filename")] public string Filename { get; set; } + [JsonProperty("description")] + public Optional Description { get; set; } + [JsonProperty("content_type")] + public Optional ContentType { get; set; } [JsonProperty("size")] public int Size { get; set; } [JsonProperty("url")] @@ -19,5 +22,7 @@ internal class Attachment public Optional Height { get; set; } [JsonProperty("width")] public Optional Width { get; set; } + [JsonProperty("ephemeral")] + public Optional Ephemeral { get; set; } } } diff --git a/src/Discord.Net.Rest/API/Common/AuditLog.cs b/src/Discord.Net.Rest/API/Common/AuditLog.cs index cd8ad147d..c8bd6d3e2 100644 --- a/src/Discord.Net.Rest/API/Common/AuditLog.cs +++ b/src/Discord.Net.Rest/API/Common/AuditLog.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace Discord.API { @@ -7,6 +7,12 @@ internal class AuditLog [JsonProperty("webhooks")] public Webhook[] Webhooks { get; set; } + [JsonProperty("threads")] + public Channel[] Threads { get; set; } + + [JsonProperty("integrations")] + public Integration[] Integrations { get; set; } + [JsonProperty("users")] public User[] Users { get; set; } diff --git a/src/Discord.Net.Rest/API/Common/AuditLogEntry.cs b/src/Discord.Net.Rest/API/Common/AuditLogEntry.cs index 7458a19cb..9626ad67e 100644 --- a/src/Discord.Net.Rest/API/Common/AuditLogEntry.cs +++ b/src/Discord.Net.Rest/API/Common/AuditLogEntry.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace Discord.API { diff --git a/src/Discord.Net.Rest/API/Common/AutocompleteInteractionData.cs b/src/Discord.Net.Rest/API/Common/AutocompleteInteractionData.cs new file mode 100644 index 000000000..2184a0e98 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/AutocompleteInteractionData.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class AutocompleteInteractionData : IDiscordInteractionData + { + [JsonProperty("id")] + public ulong Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("type")] + public ApplicationCommandType Type { get; set; } + + [JsonProperty("version")] + public ulong Version { get; set; } + + [JsonProperty("options")] + public AutocompleteInteractionDataOption[] Options { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/AutocompleteInteractionDataOption.cs b/src/Discord.Net.Rest/API/Common/AutocompleteInteractionDataOption.cs new file mode 100644 index 000000000..1419f93b6 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/AutocompleteInteractionDataOption.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class AutocompleteInteractionDataOption + { + [JsonProperty("type")] + public ApplicationCommandOptionType Type { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("options")] + public Optional Options { get; set; } + + [JsonProperty("value")] + public Optional Value { get; set; } + + [JsonProperty("focused")] + public Optional Focused { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/Ban.cs b/src/Discord.Net.Rest/API/Common/Ban.cs index 202004f53..ff47c7904 100644 --- a/src/Discord.Net.Rest/API/Common/Ban.cs +++ b/src/Discord.Net.Rest/API/Common/Ban.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/ButtonComponent.cs b/src/Discord.Net.Rest/API/Common/ButtonComponent.cs new file mode 100644 index 000000000..7f737d7ad --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/ButtonComponent.cs @@ -0,0 +1,63 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class ButtonComponent : IMessageComponent + { + [JsonProperty("type")] + public ComponentType Type { get; set; } + + [JsonProperty("style")] + public ButtonStyle Style { get; set; } + + [JsonProperty("label")] + public Optional Label { get; set; } + + [JsonProperty("emoji")] + public Optional Emote { get; set; } + + [JsonProperty("custom_id")] + public Optional CustomId { get; set; } + + [JsonProperty("url")] + public Optional Url { get; set; } + + [JsonProperty("disabled")] + public Optional Disabled { get; set; } + + public ButtonComponent() { } + + public ButtonComponent(Discord.ButtonComponent c) + { + Type = c.Type; + Style = c.Style; + Label = c.Label; + CustomId = c.CustomId; + Url = c.Url; + Disabled = c.IsDisabled; + + if (c.Emote != null) + { + if (c.Emote is Emote e) + { + Emote = new Emoji + { + Name = e.Name, + Animated = e.Animated, + Id = e.Id + }; + } + else + { + Emote = new Emoji + { + Name = c.Emote.Name + }; + } + } + } + + [JsonIgnore] + string IMessageComponent.CustomId => CustomId.GetValueOrDefault(); + } +} diff --git a/src/Discord.Net.Rest/API/Common/Channel.cs b/src/Discord.Net.Rest/API/Common/Channel.cs index 57a5ce9ab..afd219b63 100644 --- a/src/Discord.Net.Rest/API/Common/Channel.cs +++ b/src/Discord.Net.Rest/API/Common/Channel.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; using System; @@ -49,5 +48,21 @@ internal class Channel //GroupChannel [JsonProperty("icon")] public Optional Icon { get; set; } + + //ThreadChannel + [JsonProperty("member")] + public Optional ThreadMember { get; set; } + + [JsonProperty("thread_metadata")] + public Optional ThreadMetadata { get; set; } + + [JsonProperty("owner_id")] + public Optional OwnerId { get; set; } + + [JsonProperty("message_count")] + public Optional MessageCount { get; set; } + + [JsonProperty("member_count")] + public Optional MemberCount { get; set; } } } diff --git a/src/Discord.Net.Rest/API/Common/ChannelThreads.cs b/src/Discord.Net.Rest/API/Common/ChannelThreads.cs new file mode 100644 index 000000000..94b2396bf --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/ChannelThreads.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + internal class ChannelThreads + { + [JsonProperty("threads")] + public Channel[] Threads { get; set; } + + [JsonProperty("members")] + public ThreadMember[] Members { get; set; } + + [JsonProperty("has_more")] + public bool HasMore { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/Connection.cs b/src/Discord.Net.Rest/API/Common/Connection.cs index ad0a76ac1..bd8de3902 100644 --- a/src/Discord.Net.Rest/API/Common/Connection.cs +++ b/src/Discord.Net.Rest/API/Common/Connection.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; using System.Collections.Generic; diff --git a/src/Discord.Net.Rest/API/Common/DiscordError.cs b/src/Discord.Net.Rest/API/Common/DiscordError.cs new file mode 100644 index 000000000..ac1e5e13d --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/DiscordError.cs @@ -0,0 +1,20 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API +{ + [JsonConverter(typeof(Discord.Net.Converters.DiscordErrorConverter))] + internal class DiscordError + { + [JsonProperty("message")] + public string Message { get; set; } + [JsonProperty("code")] + public DiscordErrorCode Code { get; set; } + [JsonProperty("errors")] + public Optional Errors { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/Embed.cs b/src/Discord.Net.Rest/API/Common/Embed.cs index fbf20d987..77efa12aa 100644 --- a/src/Discord.Net.Rest/API/Common/Embed.cs +++ b/src/Discord.Net.Rest/API/Common/Embed.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using System; using Newtonsoft.Json; using Discord.Net.Converters; diff --git a/src/Discord.Net.Rest/API/Common/EmbedImage.cs b/src/Discord.Net.Rest/API/Common/EmbedImage.cs index e650d99f4..6b5db0681 100644 --- a/src/Discord.Net.Rest/API/Common/EmbedImage.cs +++ b/src/Discord.Net.Rest/API/Common/EmbedImage.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/EmbedProvider.cs b/src/Discord.Net.Rest/API/Common/EmbedProvider.cs index e01261483..ed0f7c3c8 100644 --- a/src/Discord.Net.Rest/API/Common/EmbedProvider.cs +++ b/src/Discord.Net.Rest/API/Common/EmbedProvider.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/EmbedThumbnail.cs b/src/Discord.Net.Rest/API/Common/EmbedThumbnail.cs index 9c87ca46b..dd25a1a26 100644 --- a/src/Discord.Net.Rest/API/Common/EmbedThumbnail.cs +++ b/src/Discord.Net.Rest/API/Common/EmbedThumbnail.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/EmbedVideo.cs b/src/Discord.Net.Rest/API/Common/EmbedVideo.cs index 3a034d244..f668217f0 100644 --- a/src/Discord.Net.Rest/API/Common/EmbedVideo.cs +++ b/src/Discord.Net.Rest/API/Common/EmbedVideo.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/Emoji.cs b/src/Discord.Net.Rest/API/Common/Emoji.cs index 945cc6d7e..ff0baa73e 100644 --- a/src/Discord.Net.Rest/API/Common/Emoji.cs +++ b/src/Discord.Net.Rest/API/Common/Emoji.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/Error.cs b/src/Discord.Net.Rest/API/Common/Error.cs new file mode 100644 index 000000000..a2b1777a3 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/Error.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class Error + { + [JsonProperty("code")] + public string Code { get; set; } + [JsonProperty("message")] + public string Message { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/Game.cs b/src/Discord.Net.Rest/API/Common/Game.cs index d3a618697..105ce0d73 100644 --- a/src/Discord.Net.Rest/API/Common/Game.cs +++ b/src/Discord.Net.Rest/API/Common/Game.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using System.Runtime.Serialization; @@ -41,6 +40,8 @@ internal class Game public Optional Emoji { get; set; } [JsonProperty("created_at")] public Optional CreatedAt { get; set; } + //[JsonProperty("buttons")] + //public Optional Buttons { get; set; } [OnError] internal void OnError(StreamingContext context, ErrorContext errorContext) diff --git a/src/Discord.Net.Rest/API/Common/Guild.cs b/src/Discord.Net.Rest/API/Common/Guild.cs index bd25c7e1a..d550c54a0 100644 --- a/src/Discord.Net.Rest/API/Common/Guild.cs +++ b/src/Discord.Net.Rest/API/Common/Guild.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API @@ -36,7 +35,7 @@ internal class Guild [JsonProperty("emojis")] public Emoji[] Emojis { get; set; } [JsonProperty("features")] - public string[] Features { get; set; } + public GuildFeatures Features { get; set; } [JsonProperty("mfa_level")] public MfaLevel MfaLevel { get; set; } [JsonProperty("application_id")] @@ -76,5 +75,13 @@ internal class Guild public Optional ApproximateMemberCount { get; set; } [JsonProperty("approximate_presence_count")] public Optional ApproximatePresenceCount { get; set; } + [JsonProperty("threads")] + public Optional Threads { get; set; } + [JsonProperty("nsfw_level")] + public NsfwLevel NsfwLevel { get; set; } + [JsonProperty("stickers")] + public Sticker[] Stickers { get; set; } + [JsonProperty("premium_progress_bar_enabled")] + public Optional IsBoostProgressBarEnabled { get; set; } } } diff --git a/src/Discord.Net.Rest/API/Common/GuildApplicationCommandPermissions.cs b/src/Discord.Net.Rest/API/Common/GuildApplicationCommandPermissions.cs new file mode 100644 index 000000000..cc74299f7 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/GuildApplicationCommandPermissions.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class GuildApplicationCommandPermission + { + [JsonProperty("id")] + public ulong Id { get; set; } + + [JsonProperty("application_id")] + public ulong ApplicationId { get; set; } + + [JsonProperty("guild_id")] + public ulong GuildId { get; set; } + + [JsonProperty("permissions")] + public ApplicationCommandPermissions[] Permissions { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/GuildMember.cs b/src/Discord.Net.Rest/API/Common/GuildMember.cs index fc2092d6c..9b888e86a 100644 --- a/src/Discord.Net.Rest/API/Common/GuildMember.cs +++ b/src/Discord.Net.Rest/API/Common/GuildMember.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; using System; @@ -10,6 +9,8 @@ internal class GuildMember public User User { get; set; } [JsonProperty("nick")] public Optional Nick { get; set; } + [JsonProperty("avatar")] + public Optional Avatar { get; set; } [JsonProperty("roles")] public Optional Roles { get; set; } [JsonProperty("joined_at")] diff --git a/src/Discord.Net.Rest/API/Common/GuildScheduledEvent.cs b/src/Discord.Net.Rest/API/Common/GuildScheduledEvent.cs new file mode 100644 index 000000000..338c24dc9 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/GuildScheduledEvent.cs @@ -0,0 +1,43 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API +{ + internal class GuildScheduledEvent + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("guild_id")] + public ulong GuildId { get; set; } + [JsonProperty("channel_id")] + public Optional ChannelId { get; set; } + [JsonProperty("creator_id")] + public Optional CreatorId { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("description")] + public Optional Description { get; set; } + [JsonProperty("scheduled_start_time")] + public DateTimeOffset ScheduledStartTime { get; set; } + [JsonProperty("scheduled_end_time")] + public DateTimeOffset? ScheduledEndTime { get; set; } + [JsonProperty("privacy_level")] + public GuildScheduledEventPrivacyLevel PrivacyLevel { get; set; } + [JsonProperty("status")] + public GuildScheduledEventStatus Status { get; set; } + [JsonProperty("entity_type")] + public GuildScheduledEventType EntityType { get; set; } + [JsonProperty("entity_id")] + public ulong? EntityId { get; set; } + [JsonProperty("entity_metadata")] + public GuildScheduledEventEntityMetadata EntityMetadata { get; set; } + [JsonProperty("creator")] + public Optional Creator { get; set; } + [JsonProperty("user_count")] + public Optional UserCount { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/GuildScheduledEventEntityMetadata.cs b/src/Discord.Net.Rest/API/Common/GuildScheduledEventEntityMetadata.cs new file mode 100644 index 000000000..1db38c0ae --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/GuildScheduledEventEntityMetadata.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API +{ + internal class GuildScheduledEventEntityMetadata + { + [JsonProperty("location")] + public Optional Location { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/GuildScheduledEventUser.cs b/src/Discord.Net.Rest/API/Common/GuildScheduledEventUser.cs new file mode 100644 index 000000000..1b0b93763 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/GuildScheduledEventUser.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API +{ + internal class GuildScheduledEventUser + { + [JsonProperty("user")] + public User User { get; set; } + [JsonProperty("member")] + public Optional Member { get; set; } + [JsonProperty("guild_scheduled_event_id")] + public ulong GuildScheduledEventId { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/GuildWidget.cs b/src/Discord.Net.Rest/API/Common/GuildWidget.cs index c15ad8aac..6b1d29cce 100644 --- a/src/Discord.Net.Rest/API/Common/GuildWidget.cs +++ b/src/Discord.Net.Rest/API/Common/GuildWidget.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/InstallParams.cs b/src/Discord.Net.Rest/API/Common/InstallParams.cs new file mode 100644 index 000000000..1fb987f30 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/InstallParams.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API +{ + internal class InstallParams + { + [JsonProperty("scopes")] + public string[] Scopes { get; set; } + [JsonProperty("permissions")] + public ulong Permission { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/Integration.cs b/src/Discord.Net.Rest/API/Common/Integration.cs index 821359975..47d67e149 100644 --- a/src/Discord.Net.Rest/API/Common/Integration.cs +++ b/src/Discord.Net.Rest/API/Common/Integration.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; using System; diff --git a/src/Discord.Net.Rest/API/Common/IntegrationAccount.cs b/src/Discord.Net.Rest/API/Common/IntegrationAccount.cs index 22831e795..a8d33931c 100644 --- a/src/Discord.Net.Rest/API/Common/IntegrationAccount.cs +++ b/src/Discord.Net.Rest/API/Common/IntegrationAccount.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/Interaction.cs b/src/Discord.Net.Rest/API/Common/Interaction.cs new file mode 100644 index 000000000..7f953384d --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/Interaction.cs @@ -0,0 +1,41 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + [JsonConverter(typeof(Net.Converters.InteractionConverter))] + internal class Interaction + { + [JsonProperty("id")] + public ulong Id { get; set; } + + [JsonProperty("application_id")] + public ulong ApplicationId { get; set; } + + [JsonProperty("type")] + public InteractionType Type { get; set; } + + [JsonProperty("data")] + public Optional Data { get; set; } + + [JsonProperty("guild_id")] + public Optional GuildId { get; set; } + + [JsonProperty("channel_id")] + public Optional ChannelId { get; set; } + + [JsonProperty("member")] + public Optional Member { get; set; } + + [JsonProperty("user")] + public Optional User { get; set; } + + [JsonProperty("token")] + public string Token { get; set; } + + [JsonProperty("version")] + public int Version { get; set; } + + [JsonProperty("message")] + public Optional Message { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/InteractionCallbackData.cs b/src/Discord.Net.Rest/API/Common/InteractionCallbackData.cs new file mode 100644 index 000000000..b07ebff49 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/InteractionCallbackData.cs @@ -0,0 +1,28 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class InteractionCallbackData + { + [JsonProperty("tts")] + public Optional TTS { get; set; } + + [JsonProperty("content")] + public Optional Content { get; set; } + + [JsonProperty("embeds")] + public Optional Embeds { get; set; } + + [JsonProperty("allowed_mentions")] + public Optional AllowedMentions { get; set; } + + [JsonProperty("flags")] + public Optional Flags { get; set; } + + [JsonProperty("components")] + public Optional Components { get; set; } + + [JsonProperty("choices")] + public Optional Choices { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/InteractionResponse.cs b/src/Discord.Net.Rest/API/Common/InteractionResponse.cs new file mode 100644 index 000000000..93d4cd307 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/InteractionResponse.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class InteractionResponse + { + [JsonProperty("type")] + public InteractionResponseType Type { get; set; } + + [JsonProperty("data")] + public Optional Data { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/Invite.cs b/src/Discord.Net.Rest/API/Common/Invite.cs index aba267f34..f9d53bad6 100644 --- a/src/Discord.Net.Rest/API/Common/Invite.cs +++ b/src/Discord.Net.Rest/API/Common/Invite.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/InviteChannel.cs b/src/Discord.Net.Rest/API/Common/InviteChannel.cs index f8f2a34f2..d601e65fe 100644 --- a/src/Discord.Net.Rest/API/Common/InviteChannel.cs +++ b/src/Discord.Net.Rest/API/Common/InviteChannel.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/InviteGuild.cs b/src/Discord.Net.Rest/API/Common/InviteGuild.cs index 3d6d7cd74..f5c634e4e 100644 --- a/src/Discord.Net.Rest/API/Common/InviteGuild.cs +++ b/src/Discord.Net.Rest/API/Common/InviteGuild.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/InviteMetadata.cs b/src/Discord.Net.Rest/API/Common/InviteMetadata.cs index f818de699..a06d06969 100644 --- a/src/Discord.Net.Rest/API/Common/InviteMetadata.cs +++ b/src/Discord.Net.Rest/API/Common/InviteMetadata.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; using System; diff --git a/src/Discord.Net.Rest/API/Common/InviteVanity.cs b/src/Discord.Net.Rest/API/Common/InviteVanity.cs index a36ddee46..412795aa6 100644 --- a/src/Discord.Net.Rest/API/Common/InviteVanity.cs +++ b/src/Discord.Net.Rest/API/Common/InviteVanity.cs @@ -2,10 +2,20 @@ namespace Discord.API { + /// + /// Represents a vanity invite. + /// public class InviteVanity { + /// + /// The unique code for the invite link. + /// [JsonProperty("code")] public string Code { get; set; } + + /// + /// The total amount of vanity invite uses. + /// [JsonProperty("uses")] public int Uses { get; set; } } diff --git a/src/Discord.Net.Rest/API/Common/Message.cs b/src/Discord.Net.Rest/API/Common/Message.cs index 6ea2c29ff..d33a03fe5 100644 --- a/src/Discord.Net.Rest/API/Common/Message.cs +++ b/src/Discord.Net.Rest/API/Common/Message.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; using System; @@ -33,7 +32,7 @@ internal class Message [JsonProperty("mention_everyone")] public Optional MentionEveryone { get; set; } [JsonProperty("mentions")] - public Optional[]> UserMentions { get; set; } + public Optional UserMentions { get; set; } [JsonProperty("mention_roles")] public Optional RoleMentions { get; set; } [JsonProperty("attachments")] @@ -58,7 +57,10 @@ internal class Message public Optional AllowedMentions { get; set; } [JsonProperty("referenced_message")] public Optional ReferencedMessage { get; set; } - [JsonProperty("stickers")] - public Optional Stickers { get; set; } + [JsonProperty("components")] + public Optional Components { get; set; } + public Optional Interaction { get; set; } + [JsonProperty("sticker_items")] + public Optional StickerItems { get; set; } } } diff --git a/src/Discord.Net.Rest/API/Common/MessageComponentInteractionData.cs b/src/Discord.Net.Rest/API/Common/MessageComponentInteractionData.cs new file mode 100644 index 000000000..a7760911c --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/MessageComponentInteractionData.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class MessageComponentInteractionData : IDiscordInteractionData + { + [JsonProperty("custom_id")] + public string CustomId { get; set; } + + [JsonProperty("component_type")] + public ComponentType ComponentType { get; set; } + + [JsonProperty("values")] + public Optional Values { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/MessageInteraction.cs b/src/Discord.Net.Rest/API/Common/MessageInteraction.cs new file mode 100644 index 000000000..48f278396 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/MessageInteraction.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API +{ + internal class MessageInteraction + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("type")] + public InteractionType Type { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("user")] + public User User { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/NitroStickerPacks.cs b/src/Discord.Net.Rest/API/Common/NitroStickerPacks.cs new file mode 100644 index 000000000..cc2f0d963 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/NitroStickerPacks.cs @@ -0,0 +1,11 @@ +using Newtonsoft.Json; +using System.Collections.Generic; + +namespace Discord.API +{ + internal class NitroStickerPacks + { + [JsonProperty("sticker_packs")] + public List StickerPacks { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/Overwrite.cs b/src/Discord.Net.Rest/API/Common/Overwrite.cs index 3d94b0640..a1fb534d8 100644 --- a/src/Discord.Net.Rest/API/Common/Overwrite.cs +++ b/src/Discord.Net.Rest/API/Common/Overwrite.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/Presence.cs b/src/Discord.Net.Rest/API/Common/Presence.cs index b44e9185d..23f871ae6 100644 --- a/src/Discord.Net.Rest/API/Common/Presence.cs +++ b/src/Discord.Net.Rest/API/Common/Presence.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; using System; using System.Collections.Generic; diff --git a/src/Discord.Net.Rest/API/Common/PropertyErrorDescription.cs b/src/Discord.Net.Rest/API/Common/PropertyErrorDescription.cs new file mode 100644 index 000000000..145288e5d --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/PropertyErrorDescription.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API +{ + internal class ErrorDetails + { + [JsonProperty("name")] + public Optional Name { get; set; } + [JsonProperty("errors")] + public Error[] Errors { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/ReadState.cs b/src/Discord.Net.Rest/API/Common/ReadState.cs index 6ea6e4bd0..9a66880c6 100644 --- a/src/Discord.Net.Rest/API/Common/ReadState.cs +++ b/src/Discord.Net.Rest/API/Common/ReadState.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/Relationship.cs b/src/Discord.Net.Rest/API/Common/Relationship.cs index ecbb96f80..d17f766af 100644 --- a/src/Discord.Net.Rest/API/Common/Relationship.cs +++ b/src/Discord.Net.Rest/API/Common/Relationship.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/RelationshipType.cs b/src/Discord.Net.Rest/API/Common/RelationshipType.cs index 0ed99f396..776ba156b 100644 --- a/src/Discord.Net.Rest/API/Common/RelationshipType.cs +++ b/src/Discord.Net.Rest/API/Common/RelationshipType.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 namespace Discord.API { internal enum RelationshipType diff --git a/src/Discord.Net.Rest/API/Common/Role.cs b/src/Discord.Net.Rest/API/Common/Role.cs index c655175da..81f54ccc0 100644 --- a/src/Discord.Net.Rest/API/Common/Role.cs +++ b/src/Discord.Net.Rest/API/Common/Role.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API @@ -9,6 +8,10 @@ internal class Role public ulong Id { get; set; } [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("icon")] + public Optional Icon { get; set; } + [JsonProperty("unicode_emoji")] + public Optional Emoji { get; set; } [JsonProperty("color")] public uint Color { get; set; } [JsonProperty("hoist")] diff --git a/src/Discord.Net.Rest/API/Common/RoleTags.cs b/src/Discord.Net.Rest/API/Common/RoleTags.cs index 6446f2037..9ddd39a64 100644 --- a/src/Discord.Net.Rest/API/Common/RoleTags.cs +++ b/src/Discord.Net.Rest/API/Common/RoleTags.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/SelectMenuComponent.cs b/src/Discord.Net.Rest/API/Common/SelectMenuComponent.cs new file mode 100644 index 000000000..0886a8fe9 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/SelectMenuComponent.cs @@ -0,0 +1,42 @@ +using Newtonsoft.Json; +using System.Linq; + +namespace Discord.API +{ + internal class SelectMenuComponent : IMessageComponent + { + [JsonProperty("type")] + public ComponentType Type { get; set; } + + [JsonProperty("custom_id")] + public string CustomId { get; set; } + + [JsonProperty("options")] + public SelectMenuOption[] Options { get; set; } + + [JsonProperty("placeholder")] + public Optional Placeholder { get; set; } + + [JsonProperty("min_values")] + public int MinValues { get; set; } + + [JsonProperty("max_values")] + public int MaxValues { get; set; } + + [JsonProperty("disabled")] + public bool Disabled { get; set; } + + public SelectMenuComponent() { } + + public SelectMenuComponent(Discord.SelectMenuComponent component) + { + Type = component.Type; + CustomId = component.CustomId; + Options = component.Options.Select(x => new SelectMenuOption(x)).ToArray(); + Placeholder = component.Placeholder; + MinValues = component.MinValues; + MaxValues = component.MaxValues; + Disabled = component.IsDisabled; + } + } +} diff --git a/src/Discord.Net.Rest/API/Common/SelectMenuOption.cs b/src/Discord.Net.Rest/API/Common/SelectMenuOption.cs new file mode 100644 index 000000000..d0a25a829 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/SelectMenuOption.cs @@ -0,0 +1,53 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class SelectMenuOption + { + [JsonProperty("label")] + public string Label { get; set; } + + [JsonProperty("value")] + public string Value { get; set; } + + [JsonProperty("description")] + public Optional Description { get; set; } + + [JsonProperty("emoji")] + public Optional Emoji { get; set; } + + [JsonProperty("default")] + public Optional Default { get; set; } + + public SelectMenuOption() { } + + public SelectMenuOption(Discord.SelectMenuOption option) + { + Label = option.Label; + Value = option.Value; + Description = option.Description; + + if (option.Emote != null) + { + if (option.Emote is Emote e) + { + Emoji = new Emoji + { + Name = e.Name, + Animated = e.Animated, + Id = e.Id + }; + } + else + { + Emoji = new Emoji + { + Name = option.Emote.Name + }; + } + } + + Default = option.IsDefault ?? Optional.Unspecified; + } + } +} diff --git a/src/Discord.Net.Rest/API/Common/StageInstance.cs b/src/Discord.Net.Rest/API/Common/StageInstance.cs new file mode 100644 index 000000000..3ec623949 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/StageInstance.cs @@ -0,0 +1,25 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class StageInstance + { + [JsonProperty("id")] + public ulong Id { get; set; } + + [JsonProperty("guild_id")] + public ulong GuildId { get; set; } + + [JsonProperty("channel_id")] + public ulong ChannelId { get; set; } + + [JsonProperty("topic")] + public string Topic { get; set; } + + [JsonProperty("privacy_level")] + public StagePrivacyLevel PrivacyLevel { get; set; } + + [JsonProperty("discoverable_disabled")] + public bool DiscoverableDisabled { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/Sticker.cs b/src/Discord.Net.Rest/API/Common/Sticker.cs index 0d1cac974..b2c58d57c 100644 --- a/src/Discord.Net.Rest/API/Common/Sticker.cs +++ b/src/Discord.Net.Rest/API/Common/Sticker.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API @@ -12,14 +11,20 @@ internal class Sticker [JsonProperty("name")] public string Name { get; set; } [JsonProperty("description")] - public string Desription { get; set; } + public string Description { get; set; } [JsonProperty("tags")] public Optional Tags { get; set; } - [JsonProperty("asset")] - public string Asset { get; set; } - [JsonProperty("preview_asset")] - public string PreviewAsset { get; set; } + [JsonProperty("type")] + public StickerType Type { get; set; } [JsonProperty("format_type")] public StickerFormatType FormatType { get; set; } + [JsonProperty("available")] + public bool? Available { get; set; } + [JsonProperty("guild_id")] + public Optional GuildId { get; set; } + [JsonProperty("user")] + public Optional User { get; set; } + [JsonProperty("sort_value")] + public int? SortValue { get; set; } } } diff --git a/src/Discord.Net.Rest/API/Common/StickerItem.cs b/src/Discord.Net.Rest/API/Common/StickerItem.cs new file mode 100644 index 000000000..4b24f711b --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/StickerItem.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class StickerItem + { + [JsonProperty("id")] + public ulong Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("format_type")] + public StickerFormatType FormatType { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/StickerPack.cs b/src/Discord.Net.Rest/API/Common/StickerPack.cs new file mode 100644 index 000000000..3daaac5bf --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/StickerPack.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Discord.API +{ + internal class StickerPack + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("stickers")] + public Sticker[] Stickers { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("sku_id")] + public ulong SkuId { get; set; } + [JsonProperty("cover_sticker_id")] + public Optional CoverStickerId { get; set; } + [JsonProperty("description")] + public string Description { get; set; } + [JsonProperty("banner_asset_id")] + public ulong BannerAssetId { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/Team.cs b/src/Discord.Net.Rest/API/Common/Team.cs index 852368522..b421dc18c 100644 --- a/src/Discord.Net.Rest/API/Common/Team.cs +++ b/src/Discord.Net.Rest/API/Common/Team.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/TeamMember.cs b/src/Discord.Net.Rest/API/Common/TeamMember.cs index 788f73b61..f3cba608e 100644 --- a/src/Discord.Net.Rest/API/Common/TeamMember.cs +++ b/src/Discord.Net.Rest/API/Common/TeamMember.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/ThreadMember.cs b/src/Discord.Net.Rest/API/Common/ThreadMember.cs new file mode 100644 index 000000000..3e30d2c95 --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/ThreadMember.cs @@ -0,0 +1,26 @@ +using Newtonsoft.Json; +using System; + +namespace Discord.API +{ + internal class ThreadMember + { + [JsonProperty("id")] + public Optional Id { get; set; } + + [JsonProperty("user_id")] + public Optional UserId { get; set; } + + [JsonProperty("join_timestamp")] + public DateTimeOffset JoinTimestamp { get; set; } + + [JsonProperty("presence")] + public Optional Presence { get; set; } + + [JsonProperty("member")] + public Optional Member { get; set; } + + [JsonProperty("flags")] + public int Flags { get; set; } // No enum type (yet?) + } +} diff --git a/src/Discord.Net.Rest/API/Common/ThreadMetadata.cs b/src/Discord.Net.Rest/API/Common/ThreadMetadata.cs new file mode 100644 index 000000000..39e9bd13e --- /dev/null +++ b/src/Discord.Net.Rest/API/Common/ThreadMetadata.cs @@ -0,0 +1,20 @@ +using Newtonsoft.Json; +using System; + +namespace Discord.API +{ + internal class ThreadMetadata + { + [JsonProperty("archived")] + public bool Archived { get; set; } + + [JsonProperty("auto_archive_duration")] + public ThreadArchiveDuration AutoArchiveDuration { get; set; } + + [JsonProperty("archive_timestamp")] + public DateTimeOffset ArchiveTimestamp { get; set; } + + [JsonProperty("locked")] + public Optional Locked { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Common/User.cs b/src/Discord.Net.Rest/API/Common/User.cs index d1f436afb..08fe88cb0 100644 --- a/src/Discord.Net.Rest/API/Common/User.cs +++ b/src/Discord.Net.Rest/API/Common/User.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API @@ -15,6 +14,10 @@ internal class User public Optional Bot { get; set; } [JsonProperty("avatar")] public Optional Avatar { get; set; } + [JsonProperty("banner")] + public Optional Banner { get; set; } + [JsonProperty("accent_color")] + public Optional AccentColor { get; set; } //CurrentUser [JsonProperty("verified")] diff --git a/src/Discord.Net.Rest/API/Common/UserGuild.cs b/src/Discord.Net.Rest/API/Common/UserGuild.cs index 825e9a09a..fc1fe833d 100644 --- a/src/Discord.Net.Rest/API/Common/UserGuild.cs +++ b/src/Discord.Net.Rest/API/Common/UserGuild.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/VoiceRegion.cs b/src/Discord.Net.Rest/API/Common/VoiceRegion.cs index 606af07bd..3cc66a0ef 100644 --- a/src/Discord.Net.Rest/API/Common/VoiceRegion.cs +++ b/src/Discord.Net.Rest/API/Common/VoiceRegion.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Common/VoiceState.cs b/src/Discord.Net.Rest/API/Common/VoiceState.cs index c7a571ed0..f7cd54a72 100644 --- a/src/Discord.Net.Rest/API/Common/VoiceState.cs +++ b/src/Discord.Net.Rest/API/Common/VoiceState.cs @@ -1,5 +1,5 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; +using System; namespace Discord.API { @@ -28,5 +28,7 @@ internal class VoiceState public bool Suppress { get; set; } [JsonProperty("self_stream")] public bool SelfStream { get; set; } + [JsonProperty("request_to_speak_timestamp")] + public Optional RequestToSpeakTimestamp { get; set; } } } diff --git a/src/Discord.Net.Rest/API/Common/Webhook.cs b/src/Discord.Net.Rest/API/Common/Webhook.cs index cbd5fdad5..23b682bd3 100644 --- a/src/Discord.Net.Rest/API/Common/Webhook.cs +++ b/src/Discord.Net.Rest/API/Common/Webhook.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API @@ -21,5 +20,7 @@ internal class Webhook [JsonProperty("user")] public Optional Creator { get; set; } + [JsonProperty("application_id")] + public ulong? ApplicationId { get; set; } } } diff --git a/src/Discord.Net.Rest/API/Int53Attribute.cs b/src/Discord.Net.Rest/API/Int53Attribute.cs index 70ef2f185..3a21b583d 100644 --- a/src/Discord.Net.Rest/API/Int53Attribute.cs +++ b/src/Discord.Net.Rest/API/Int53Attribute.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using System; namespace Discord.API diff --git a/src/Discord.Net.Rest/API/Net/IResolvable.cs b/src/Discord.Net.Rest/API/Net/IResolvable.cs new file mode 100644 index 000000000..7485f5de8 --- /dev/null +++ b/src/Discord.Net.Rest/API/Net/IResolvable.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API +{ + internal interface IResolvable + { + Optional Resolved { get; } + } +} diff --git a/src/Discord.Net.Rest/API/Net/MultipartFile.cs b/src/Discord.Net.Rest/API/Net/MultipartFile.cs index 604852e90..d6bc4c7ab 100644 --- a/src/Discord.Net.Rest/API/Net/MultipartFile.cs +++ b/src/Discord.Net.Rest/API/Net/MultipartFile.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; namespace Discord.Net.Rest { @@ -6,11 +6,13 @@ internal struct MultipartFile { public Stream Stream { get; } public string Filename { get; } + public string ContentType { get; } - public MultipartFile(Stream stream, string filename) + public MultipartFile(Stream stream, string filename, string contentType = null) { Stream = stream; Filename = filename; + ContentType = contentType; } } } diff --git a/src/Discord.Net.Rest/API/Rest/CreateApplicationCommandParams.cs b/src/Discord.Net.Rest/API/Rest/CreateApplicationCommandParams.cs new file mode 100644 index 000000000..82f0befcd --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/CreateApplicationCommandParams.cs @@ -0,0 +1,31 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + internal class CreateApplicationCommandParams + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("type")] + public ApplicationCommandType Type { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + [JsonProperty("options")] + public Optional Options { get; set; } + + [JsonProperty("default_permission")] + public Optional DefaultPermission { get; set; } + + public CreateApplicationCommandParams() { } + public CreateApplicationCommandParams(string name, string description, ApplicationCommandType type, ApplicationCommandOption[] options = null) + { + Name = name; + Description = description; + Options = Optional.Create(options); + Type = type; + } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/CreateChannelInviteParams.cs b/src/Discord.Net.Rest/API/Rest/CreateChannelInviteParams.cs index db79bc314..852abe301 100644 --- a/src/Discord.Net.Rest/API/Rest/CreateChannelInviteParams.cs +++ b/src/Discord.Net.Rest/API/Rest/CreateChannelInviteParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest @@ -14,5 +13,11 @@ internal class CreateChannelInviteParams public Optional IsTemporary { get; set; } [JsonProperty("unique")] public Optional IsUnique { get; set; } + [JsonProperty("target_type")] + public Optional TargetType { get; set; } + [JsonProperty("target_user_id")] + public Optional TargetUserId { get; set; } + [JsonProperty("target_application_id")] + public Optional TargetApplicationId { get; set; } } } diff --git a/src/Discord.Net.Rest/API/Rest/CreateDMChannelParams.cs b/src/Discord.Net.Rest/API/Rest/CreateDMChannelParams.cs index f32796e02..0a710dd1b 100644 --- a/src/Discord.Net.Rest/API/Rest/CreateDMChannelParams.cs +++ b/src/Discord.Net.Rest/API/Rest/CreateDMChannelParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/CreateGuildBanParams.cs b/src/Discord.Net.Rest/API/Rest/CreateGuildBanParams.cs index f0432e517..fce9df11f 100644 --- a/src/Discord.Net.Rest/API/Rest/CreateGuildBanParams.cs +++ b/src/Discord.Net.Rest/API/Rest/CreateGuildBanParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 namespace Discord.API.Rest { internal class CreateGuildBanParams diff --git a/src/Discord.Net.Rest/API/Rest/CreateGuildChannelParams.cs b/src/Discord.Net.Rest/API/Rest/CreateGuildChannelParams.cs index aec43dbef..57816e448 100644 --- a/src/Discord.Net.Rest/API/Rest/CreateGuildChannelParams.cs +++ b/src/Discord.Net.Rest/API/Rest/CreateGuildChannelParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/CreateGuildEmoteParams.cs b/src/Discord.Net.Rest/API/Rest/CreateGuildEmoteParams.cs index 308199820..c81f62f4c 100644 --- a/src/Discord.Net.Rest/API/Rest/CreateGuildEmoteParams.cs +++ b/src/Discord.Net.Rest/API/Rest/CreateGuildEmoteParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/CreateGuildIntegrationParams.cs b/src/Discord.Net.Rest/API/Rest/CreateGuildIntegrationParams.cs index 1053a0ed3..7358e5201 100644 --- a/src/Discord.Net.Rest/API/Rest/CreateGuildIntegrationParams.cs +++ b/src/Discord.Net.Rest/API/Rest/CreateGuildIntegrationParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/CreateGuildParams.cs b/src/Discord.Net.Rest/API/Rest/CreateGuildParams.cs index cda6caedf..e89c2b119 100644 --- a/src/Discord.Net.Rest/API/Rest/CreateGuildParams.cs +++ b/src/Discord.Net.Rest/API/Rest/CreateGuildParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/CreateGuildScheduledEventParams.cs b/src/Discord.Net.Rest/API/Rest/CreateGuildScheduledEventParams.cs new file mode 100644 index 000000000..a207d3374 --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/CreateGuildScheduledEventParams.cs @@ -0,0 +1,29 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API.Rest +{ + internal class CreateGuildScheduledEventParams + { + [JsonProperty("channel_id")] + public Optional ChannelId { get; set; } + [JsonProperty("entity_metadata")] + public Optional EntityMetadata { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("privacy_level")] + public GuildScheduledEventPrivacyLevel PrivacyLevel { get; set; } + [JsonProperty("scheduled_start_time")] + public DateTimeOffset StartTime { get; set; } + [JsonProperty("scheduled_end_time")] + public Optional EndTime { get; set; } + [JsonProperty("description")] + public Optional Description { get; set; } + [JsonProperty("entity_type")] + public GuildScheduledEventType Type { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/CreateMessageParams.cs b/src/Discord.Net.Rest/API/Rest/CreateMessageParams.cs index e64532864..5996c7e83 100644 --- a/src/Discord.Net.Rest/API/Rest/CreateMessageParams.cs +++ b/src/Discord.Net.Rest/API/Rest/CreateMessageParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest @@ -11,15 +10,25 @@ internal class CreateMessageParams [JsonProperty("nonce")] public Optional Nonce { get; set; } + [JsonProperty("tts")] public Optional IsTTS { get; set; } - [JsonProperty("embed")] - public Optional Embed { get; set; } + + [JsonProperty("embeds")] + public Optional Embeds { get; set; } + [JsonProperty("allowed_mentions")] public Optional AllowedMentions { get; set; } + [JsonProperty("message_reference")] public Optional MessageReference { get; set; } + [JsonProperty("components")] + public Optional Components { get; set; } + + [JsonProperty("sticker_ids")] + public Optional Stickers { get; set; } + public CreateMessageParams(string content) { Content = content; diff --git a/src/Discord.Net.Rest/API/Rest/CreateStageInstanceParams.cs b/src/Discord.Net.Rest/API/Rest/CreateStageInstanceParams.cs new file mode 100644 index 000000000..a1d59bb51 --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/CreateStageInstanceParams.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + internal class CreateStageInstanceParams + { + [JsonProperty("channel_id")] + public ulong ChannelId { get; set; } + + [JsonProperty("topic")] + public string Topic { get; set; } + + [JsonProperty("privacy_level")] + public Optional PrivacyLevel { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/CreateStickerParams.cs b/src/Discord.Net.Rest/API/Rest/CreateStickerParams.cs new file mode 100644 index 000000000..b330a0111 --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/CreateStickerParams.cs @@ -0,0 +1,35 @@ +using Discord.Net.Rest; +using System.Collections.Generic; +using System.IO; +namespace Discord.API.Rest +{ + internal class CreateStickerParams + { + public Stream File { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Tags { get; set; } + public string FileName { get; set; } + + public IReadOnlyDictionary ToDictionary() + { + var d = new Dictionary + { + ["name"] = $"{Name}", + ["description"] = Description, + ["tags"] = Tags + }; + + string contentType = "image/png"; + + if (File is FileStream fileStream) + contentType = $"image/{Path.GetExtension(fileStream.Name)}"; + else if (FileName != null) + contentType = $"image/{Path.GetExtension(FileName)}"; + + d["file"] = new MultipartFile(File, FileName ?? "image", contentType.Replace(".", "")); + + return d; + } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs b/src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs index 0a4f80a3c..bda0f7ff1 100644 --- a/src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs +++ b/src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs @@ -1,30 +1,84 @@ -#pragma warning disable CS1591 +using Discord.Net.Converters; +using Discord.Net.Rest; using Newtonsoft.Json; +using System.Collections.Generic; +using System.IO; +using System.Text; namespace Discord.API.Rest { [JsonObject(MemberSerialization = MemberSerialization.OptIn)] internal class CreateWebhookMessageParams { + private static JsonSerializer _serializer = new JsonSerializer { ContractResolver = new DiscordContractResolver() }; + [JsonProperty("content")] - public string Content { get; } + public string Content { get; set; } [JsonProperty("nonce")] public Optional Nonce { get; set; } + [JsonProperty("tts")] public Optional IsTTS { get; set; } + [JsonProperty("embeds")] public Optional Embeds { get; set; } + [JsonProperty("username")] public Optional Username { get; set; } + [JsonProperty("avatar_url")] public Optional AvatarUrl { get; set; } + [JsonProperty("allowed_mentions")] public Optional AllowedMentions { get; set; } - public CreateWebhookMessageParams(string content) + [JsonProperty("flags")] + public Optional Flags { get; set; } + + [JsonProperty("components")] + public Optional Components { get; set; } + + [JsonProperty("file")] + public Optional File { get; set; } + + public IReadOnlyDictionary ToDictionary() { - Content = content; + var d = new Dictionary(); + + if (File.IsSpecified) + { + d["file"] = File.Value; + } + + var payload = new Dictionary + { + ["content"] = Content + }; + + if (IsTTS.IsSpecified) + payload["tts"] = IsTTS.Value.ToString(); + if (Nonce.IsSpecified) + payload["nonce"] = Nonce.Value; + if (Username.IsSpecified) + payload["username"] = Username.Value; + if (AvatarUrl.IsSpecified) + payload["avatar_url"] = AvatarUrl.Value; + if (Embeds.IsSpecified) + payload["embeds"] = Embeds.Value; + if (AllowedMentions.IsSpecified) + payload["allowed_mentions"] = AllowedMentions.Value; + if (Components.IsSpecified) + payload["components"] = Components.Value; + + var json = new StringBuilder(); + using (var text = new StringWriter(json)) + using (var writer = new JsonTextWriter(text)) + _serializer.Serialize(writer, payload); + + d["payload_json"] = json.ToString(); + + return d; } } } diff --git a/src/Discord.Net.Rest/API/Rest/CreateWebhookParams.cs b/src/Discord.Net.Rest/API/Rest/CreateWebhookParams.cs index 0d1059fab..242f451cb 100644 --- a/src/Discord.Net.Rest/API/Rest/CreateWebhookParams.cs +++ b/src/Discord.Net.Rest/API/Rest/CreateWebhookParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/DeleteMessagesParams.cs b/src/Discord.Net.Rest/API/Rest/DeleteMessagesParams.cs index ca9d8c26e..ca6b78406 100644 --- a/src/Discord.Net.Rest/API/Rest/DeleteMessagesParams.cs +++ b/src/Discord.Net.Rest/API/Rest/DeleteMessagesParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/GetBotGatewayResponse.cs b/src/Discord.Net.Rest/API/Rest/GetBotGatewayResponse.cs index d3285051b..3f8318cd1 100644 --- a/src/Discord.Net.Rest/API/Rest/GetBotGatewayResponse.cs +++ b/src/Discord.Net.Rest/API/Rest/GetBotGatewayResponse.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/GetChannelMessagesParams.cs b/src/Discord.Net.Rest/API/Rest/GetChannelMessagesParams.cs index ea5327667..52dd84836 100644 --- a/src/Discord.Net.Rest/API/Rest/GetChannelMessagesParams.cs +++ b/src/Discord.Net.Rest/API/Rest/GetChannelMessagesParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 namespace Discord.API.Rest { internal class GetChannelMessagesParams diff --git a/src/Discord.Net.Rest/API/Rest/GetEventUsersParams.cs b/src/Discord.Net.Rest/API/Rest/GetEventUsersParams.cs new file mode 100644 index 000000000..db3ac666e --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/GetEventUsersParams.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API.Rest +{ + internal class GetEventUsersParams + { + public Optional Limit { get; set; } + public Optional RelativeDirection { get; set; } + public Optional RelativeUserId { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/GetGatewayResponse.cs b/src/Discord.Net.Rest/API/Rest/GetGatewayResponse.cs index ce3630170..11207633d 100644 --- a/src/Discord.Net.Rest/API/Rest/GetGatewayResponse.cs +++ b/src/Discord.Net.Rest/API/Rest/GetGatewayResponse.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/GetGuildMembersParams.cs b/src/Discord.Net.Rest/API/Rest/GetGuildMembersParams.cs index 66023cb43..67d380035 100644 --- a/src/Discord.Net.Rest/API/Rest/GetGuildMembersParams.cs +++ b/src/Discord.Net.Rest/API/Rest/GetGuildMembersParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 namespace Discord.API.Rest { internal class GetGuildMembersParams diff --git a/src/Discord.Net.Rest/API/Rest/GetGuildPruneCountResponse.cs b/src/Discord.Net.Rest/API/Rest/GetGuildPruneCountResponse.cs index 4af85acfa..1e7fc8c7b 100644 --- a/src/Discord.Net.Rest/API/Rest/GetGuildPruneCountResponse.cs +++ b/src/Discord.Net.Rest/API/Rest/GetGuildPruneCountResponse.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/GetGuildSummariesParams.cs b/src/Discord.Net.Rest/API/Rest/GetGuildSummariesParams.cs index f770ef398..1d3f70f07 100644 --- a/src/Discord.Net.Rest/API/Rest/GetGuildSummariesParams.cs +++ b/src/Discord.Net.Rest/API/Rest/GetGuildSummariesParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 namespace Discord.API.Rest { internal class GetGuildSummariesParams diff --git a/src/Discord.Net.Rest/API/Rest/GuildPruneParams.cs b/src/Discord.Net.Rest/API/Rest/GuildPruneParams.cs index e4c9192ad..c6caa1eb1 100644 --- a/src/Discord.Net.Rest/API/Rest/GuildPruneParams.cs +++ b/src/Discord.Net.Rest/API/Rest/GuildPruneParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/ModifyApplicationCommandParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyApplicationCommandParams.cs new file mode 100644 index 000000000..5891c2c28 --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/ModifyApplicationCommandParams.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + internal class ModifyApplicationCommandParams + { + [JsonProperty("name")] + public Optional Name { get; set; } + + [JsonProperty("description")] + public Optional Description { get; set; } + + [JsonProperty("options")] + public Optional Options { get; set; } + + [JsonProperty("default_permission")] + public Optional DefaultPermission { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/ModifyChannelPermissionsParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyChannelPermissionsParams.cs index 269111a61..acb81034a 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyChannelPermissionsParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyChannelPermissionsParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/ModifyCurrentUserNickParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyCurrentUserNickParams.cs index ba44e34cf..c10f2e4ec 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyCurrentUserNickParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyCurrentUserNickParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/ModifyCurrentUserParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyCurrentUserParams.cs index 7ba27c3a5..e28deb32b 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyCurrentUserParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyCurrentUserParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/ModifyGuildApplicationCommandPermissions.cs b/src/Discord.Net.Rest/API/Rest/ModifyGuildApplicationCommandPermissions.cs new file mode 100644 index 000000000..a557061f3 --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/ModifyGuildApplicationCommandPermissions.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + internal class ModifyGuildApplicationCommandPermissions + { + [JsonProperty("id")] + public ulong Id { get; set; } + + [JsonProperty("permissions")] + public ApplicationCommandPermissions[] Permissions { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/ModifyGuildApplicationCommandPermissionsParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyGuildApplicationCommandPermissionsParams.cs new file mode 100644 index 000000000..322875b8e --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/ModifyGuildApplicationCommandPermissionsParams.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + internal class ModifyGuildApplicationCommandPermissionsParams + { + [JsonProperty("permissions")] + public ApplicationCommandPermissions[] Permissions { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/ModifyGuildChannelParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyGuildChannelParams.cs index e5e8a4632..dfe9cd980 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyGuildChannelParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyGuildChannelParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/ModifyGuildChannelsParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyGuildChannelsParams.cs index f97fbda0b..91567be3d 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyGuildChannelsParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyGuildChannelsParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/ModifyGuildEmbedParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyGuildEmbedParams.cs index 487744c65..420bdbeaf 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyGuildEmbedParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyGuildEmbedParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/ModifyGuildEmoteParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyGuildEmoteParams.cs index a2295dd5d..08b196daa 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyGuildEmoteParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyGuildEmoteParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/ModifyGuildIntegrationParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyGuildIntegrationParams.cs index 0a1b4f9fa..cf869c838 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyGuildIntegrationParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyGuildIntegrationParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/ModifyGuildMemberParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyGuildMemberParams.cs index a381d6f8f..37625de09 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyGuildMemberParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyGuildMemberParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/ModifyGuildParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyGuildParams.cs index cfb107bcd..c1a20cb83 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyGuildParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyGuildParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest @@ -36,5 +35,7 @@ internal class ModifyGuildParams public Optional SystemChannelFlags { get; set; } [JsonProperty("preferred_locale")] public string PreferredLocale { get; set; } + [JsonProperty("premium_progress_bar_enabled")] + public Optional IsBoostProgressBarEnabled { get; set; } } } diff --git a/src/Discord.Net.Rest/API/Rest/ModifyGuildRoleParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyGuildRoleParams.cs index 8605411c5..fbb9c3e48 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyGuildRoleParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyGuildRoleParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest @@ -14,6 +13,8 @@ internal class ModifyGuildRoleParams public Optional Color { get; set; } [JsonProperty("hoist")] public Optional Hoist { get; set; } + [JsonProperty("icon")] + public Optional Icon { get; set; } [JsonProperty("mentionable")] public Optional Mentionable { get; set; } } diff --git a/src/Discord.Net.Rest/API/Rest/ModifyGuildRolesParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyGuildRolesParams.cs index 0e816a260..eeb724523 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyGuildRolesParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyGuildRolesParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/ModifyGuildScheduledEventParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyGuildScheduledEventParams.cs new file mode 100644 index 000000000..3d191a0b3 --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/ModifyGuildScheduledEventParams.cs @@ -0,0 +1,31 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API.Rest +{ + internal class ModifyGuildScheduledEventParams + { + [JsonProperty("channel_id")] + public Optional ChannelId { get; set; } + [JsonProperty("entity_metadata")] + public Optional EntityMetadata { get; set; } + [JsonProperty("name")] + public Optional Name { get; set; } + [JsonProperty("privacy_level")] + public Optional PrivacyLevel { get; set; } + [JsonProperty("scheduled_start_time")] + public Optional StartTime { get; set; } + [JsonProperty("scheduled_end_time")] + public Optional EndTime { get; set; } + [JsonProperty("description")] + public Optional Description { get; set; } + [JsonProperty("entity_type")] + public Optional Type { get; set; } + [JsonProperty("status")] + public Optional Status { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/ModifyGuildWidgetParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyGuildWidgetParams.cs index 506f1dfbb..2e5658d51 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyGuildWidgetParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyGuildWidgetParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/ModifyInteractionResponseParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyInteractionResponseParams.cs new file mode 100644 index 000000000..a2c7cbee6 --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/ModifyInteractionResponseParams.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + internal class ModifyInteractionResponseParams + { + [JsonProperty("content")] + public Optional Content { get; set; } + + [JsonProperty("embeds")] + public Optional Embeds { get; set; } + + [JsonProperty("allowed_mentions")] + public Optional AllowedMentions { get; set; } + + [JsonProperty("components")] + public Optional Components { get; set; } + + [JsonProperty("flags")] + public Optional Flags { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/ModifyMessageParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyMessageParams.cs index 3752df3a2..3dba45a5b 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyMessageParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyMessageParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest @@ -8,8 +7,10 @@ internal class ModifyMessageParams { [JsonProperty("content")] public Optional Content { get; set; } - [JsonProperty("embed")] - public Optional Embed { get; set; } + [JsonProperty("embeds")] + public Optional Embeds { get; set; } + [JsonProperty("components")] + public Optional Components { get; set; } [JsonProperty("flags")] public Optional Flags { get; set; } [JsonProperty("allowed_mentions")] diff --git a/src/Discord.Net.Rest/API/Rest/ModifyStageInstanceParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyStageInstanceParams.cs new file mode 100644 index 000000000..c09d8f216 --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/ModifyStageInstanceParams.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + internal class ModifyStageInstanceParams + { + [JsonProperty("topic")] + public Optional Topic { get; set; } + + [JsonProperty("privacy_level")] + public Optional PrivacyLevel { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/ModifyStickerParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyStickerParams.cs new file mode 100644 index 000000000..bd538c72e --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/ModifyStickerParams.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + internal class ModifyStickerParams + { + [JsonProperty("name")] + public Optional Name { get; set; } + [JsonProperty("description")] + public Optional Description { get; set; } + [JsonProperty("tags")] + public Optional Tags { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/ModifyTextChannelParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyTextChannelParams.cs index 94f149fc1..409d90c3f 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyTextChannelParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyTextChannelParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/ModifyThreadParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyThreadParams.cs new file mode 100644 index 000000000..8c9216c3f --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/ModifyThreadParams.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + internal class ModifyThreadParams + { + [JsonProperty("name")] + public Optional Name { get; set; } + + [JsonProperty("archived")] + public Optional Archived { get; set; } + + [JsonProperty("auto_archive_duration")] + public Optional AutoArchiveDuration { get; set; } + + [JsonProperty("locked")] + public Optional Locked { get; set; } + + [JsonProperty("rate_limit_per_user")] + public Optional Slowmode { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/ModifyVoiceChannelParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyVoiceChannelParams.cs index ce36eb11f..2f8cacc69 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyVoiceChannelParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyVoiceChannelParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest @@ -10,5 +9,7 @@ internal class ModifyVoiceChannelParams : ModifyGuildChannelParams public Optional Bitrate { get; set; } [JsonProperty("user_limit")] public Optional UserLimit { get; set; } + [JsonProperty("rtc_region")] + public Optional RTCRegion { get; set; } } } diff --git a/src/Discord.Net.Rest/API/Rest/ModifyVoiceStateParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyVoiceStateParams.cs new file mode 100644 index 000000000..1ff0f3e08 --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/ModifyVoiceStateParams.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; +using System; + +namespace Discord.API.Rest +{ + internal class ModifyVoiceStateParams + { + [JsonProperty("channel_id")] + public ulong ChannelId { get; set; } + + [JsonProperty("suppress")] + public Optional Suppressed { get; set; } + + [JsonProperty("request_to_speak_timestamp")] + public Optional RequestToSpeakTimestamp { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/ModifyWebhookMessageParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyWebhookMessageParams.cs index ba8fcbb4e..e73efaf36 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyWebhookMessageParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyWebhookMessageParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest @@ -12,5 +11,7 @@ internal class ModifyWebhookMessageParams public Optional Embeds { get; set; } [JsonProperty("allowed_mentions")] public Optional AllowedMentions { get; set; } + [JsonProperty("components")] + public Optional Components { get; set; } } } diff --git a/src/Discord.Net.Rest/API/Rest/ModifyWebhookParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyWebhookParams.cs index 0f2d6e33b..2e4e6a4c4 100644 --- a/src/Discord.Net.Rest/API/Rest/ModifyWebhookParams.cs +++ b/src/Discord.Net.Rest/API/Rest/ModifyWebhookParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Rest diff --git a/src/Discord.Net.Rest/API/Rest/SearchGuildMembersParams.cs b/src/Discord.Net.Rest/API/Rest/SearchGuildMembersParams.cs index 7c933ff82..56b3595fa 100644 --- a/src/Discord.Net.Rest/API/Rest/SearchGuildMembersParams.cs +++ b/src/Discord.Net.Rest/API/Rest/SearchGuildMembersParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 namespace Discord.API.Rest { internal class SearchGuildMembersParams diff --git a/src/Discord.Net.Rest/API/Rest/StartThreadParams.cs b/src/Discord.Net.Rest/API/Rest/StartThreadParams.cs new file mode 100644 index 000000000..a13161cd4 --- /dev/null +++ b/src/Discord.Net.Rest/API/Rest/StartThreadParams.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + internal class StartThreadParams + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("auto_archive_duration")] + public ThreadArchiveDuration Duration { get; set; } + + [JsonProperty("type")] + public ThreadType Type { get; set; } + + [JsonProperty("invitable")] + public Optional Invitable { get; set; } + + [JsonProperty("rate_limit_per_user")] + public Optional Ratelimit { get; set; } + } +} diff --git a/src/Discord.Net.Rest/API/Rest/UploadFileParams.cs b/src/Discord.Net.Rest/API/Rest/UploadFileParams.cs index dd442a6de..6340c3e38 100644 --- a/src/Discord.Net.Rest/API/Rest/UploadFileParams.cs +++ b/src/Discord.Net.Rest/API/Rest/UploadFileParams.cs @@ -1,9 +1,9 @@ -#pragma warning disable CS1591 using Discord.Net.Converters; using Discord.Net.Rest; using Newtonsoft.Json; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; namespace Discord.API.Rest @@ -12,30 +12,27 @@ internal class UploadFileParams { private static JsonSerializer _serializer = new JsonSerializer { ContractResolver = new DiscordContractResolver() }; - public Stream File { get; } + public FileAttachment[] Files { get; } - public Optional Filename { get; set; } public Optional Content { get; set; } public Optional Nonce { get; set; } public Optional IsTTS { get; set; } - public Optional Embed { get; set; } + public Optional Embeds { get; set; } public Optional AllowedMentions { get; set; } public Optional MessageReference { get; set; } - public bool IsSpoiler { get; set; } = false; + public Optional MessageComponent { get; set; } + public Optional Flags { get; set; } + public Optional Stickers { get; set; } - public UploadFileParams(Stream file) + public UploadFileParams(params Discord.FileAttachment[] attachments) { - File = file; + Files = attachments; } public IReadOnlyDictionary ToDictionary() { var d = new Dictionary(); - var filename = Filename.GetValueOrDefault("unknown.dat"); - if (IsSpoiler && !filename.StartsWith(AttachmentExtensions.SpoilerPrefix)) - filename = filename.Insert(0, AttachmentExtensions.SpoilerPrefix); - d["file"] = new MultipartFile(File, filename); - + var payload = new Dictionary(); if (Content.IsSpecified) payload["content"] = Content.Value; @@ -43,14 +40,39 @@ public IReadOnlyDictionary ToDictionary() payload["tts"] = IsTTS.Value.ToString(); if (Nonce.IsSpecified) payload["nonce"] = Nonce.Value; - if (Embed.IsSpecified) - payload["embed"] = Embed.Value; + if (Embeds.IsSpecified) + payload["embeds"] = Embeds.Value; if (AllowedMentions.IsSpecified) payload["allowed_mentions"] = AllowedMentions.Value; - if (IsSpoiler) - payload["hasSpoiler"] = IsSpoiler.ToString(); + if (MessageComponent.IsSpecified) + payload["components"] = MessageComponent.Value; if (MessageReference.IsSpecified) payload["message_reference"] = MessageReference.Value; + if (Stickers.IsSpecified) + payload["sticker_ids"] = Stickers.Value; + if (Flags.IsSpecified) + payload["flags"] = Flags; + + List attachments = new(); + + for(int n = 0; n != Files.Length; n++) + { + var attachment = Files[n]; + + var filename = attachment.FileName ?? "unknown.dat"; + if (attachment.IsSpoiler && !filename.StartsWith(AttachmentExtensions.SpoilerPrefix)) + filename = filename.Insert(0, AttachmentExtensions.SpoilerPrefix); + d[$"files[{n}]"] = new MultipartFile(attachment.Stream, filename); + + attachments.Add(new + { + id = (ulong)n, + filename = filename, + description = attachment.Description ?? Optional.Unspecified + }); + } + + payload["attachments"] = attachments; var json = new StringBuilder(); using (var text = new StringWriter(json)) diff --git a/src/Discord.Net.Rest/API/Rest/UploadWebhookFileParams.cs b/src/Discord.Net.Rest/API/Rest/UploadWebhookFileParams.cs index 8da7681ae..d925e0108 100644 --- a/src/Discord.Net.Rest/API/Rest/UploadWebhookFileParams.cs +++ b/src/Discord.Net.Rest/API/Rest/UploadWebhookFileParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using System.Collections.Generic; using System.IO; using System.Text; diff --git a/src/Discord.Net.Rest/BaseDiscordClient.cs b/src/Discord.Net.Rest/BaseDiscordClient.cs index 68589a4f1..525875232 100644 --- a/src/Discord.Net.Rest/BaseDiscordClient.cs +++ b/src/Discord.Net.Rest/BaseDiscordClient.cs @@ -10,6 +10,7 @@ namespace Discord.Rest { public abstract class BaseDiscordClient : IDiscordClient { + #region BaseDiscordClient public event Func Log { add { _logEvent.Add(value); } remove { _logEvent.Remove(value); } } internal readonly AsyncEvent> _logEvent = new AsyncEvent>(); @@ -34,6 +35,7 @@ public abstract class BaseDiscordClient : IDiscordClient public ISelfUser CurrentUser { get; protected set; } /// public TokenType TokenType => ApiClient.AuthTokenType; + internal bool UseInteractionSnowflakeDate { get; private set; } /// Creates a new REST-only Discord client. internal BaseDiscordClient(DiscordRestConfig config, API.DiscordRestApiClient client) @@ -46,6 +48,8 @@ internal BaseDiscordClient(DiscordRestConfig config, API.DiscordRestApiClient cl _restLogger = LogManager.CreateLogger("Rest"); _isFirstLogin = config.DisplayInitialLog; + UseInteractionSnowflakeDate = config.UseInteractionSnowflakeDate; + ApiClient.RequestQueue.RateLimitTriggered += async (id, info, endpoint) => { if (info == null) @@ -155,8 +159,9 @@ public Task GetRecommendedShardCountAsync(RequestOptions options = null) /// public Task GetBotGatewayAsync(RequestOptions options = null) => ClientHelper.GetBotGatewayAsync(this, options); + #endregion - //IDiscordClient + #region IDiscordClient /// ConnectionState IDiscordClient.ConnectionState => ConnectionState.Disconnected; /// @@ -216,11 +221,25 @@ Task IDiscordClient.GetVoiceRegionAsync(string id, RequestOptions Task IDiscordClient.GetWebhookAsync(ulong id, RequestOptions options) => Task.FromResult(null); + /// + Task IDiscordClient.GetGlobalApplicationCommandAsync(ulong id, RequestOptions options) + => Task.FromResult(null); + + /// + Task> IDiscordClient.GetGlobalApplicationCommandsAsync(RequestOptions options) + => Task.FromResult>(ImmutableArray.Create()); + Task IDiscordClient.CreateGlobalApplicationCommand(ApplicationCommandProperties properties, RequestOptions options) + => Task.FromResult(null); + Task> IDiscordClient.BulkOverwriteGlobalApplicationCommand(ApplicationCommandProperties[] properties, + RequestOptions options) + => Task.FromResult>(ImmutableArray.Create()); + /// Task IDiscordClient.StartAsync() => Task.Delay(0); /// Task IDiscordClient.StopAsync() => Task.Delay(0); + #endregion } } diff --git a/src/Discord.Net.Rest/ClientHelper.cs b/src/Discord.Net.Rest/ClientHelper.cs index 3ff8212fe..5debea27e 100644 --- a/src/Discord.Net.Rest/ClientHelper.cs +++ b/src/Discord.Net.Rest/ClientHelper.cs @@ -10,7 +10,7 @@ namespace Discord.Rest { internal static class ClientHelper { - //Applications + #region Applications public static async Task GetApplicationInfoAsync(BaseDiscordClient client, RequestOptions options) { var model = await client.ApiClient.GetMyApplicationAsync(options).ConfigureAwait(false); @@ -193,9 +193,76 @@ public static async Task GetBotGatewayAsync(BaseDiscordClient client } }; } + + public static async Task> GetGlobalApplicationCommandsAsync(BaseDiscordClient client, + RequestOptions options = null) + { + var response = await client.ApiClient.GetGlobalApplicationCommandsAsync(options).ConfigureAwait(false); + + if (!response.Any()) + return Array.Empty(); + + return response.Select(x => RestGlobalCommand.Create(client, x)).ToArray(); + } + public static async Task GetGlobalApplicationCommandAsync(BaseDiscordClient client, ulong id, + RequestOptions options = null) + { + var model = await client.ApiClient.GetGlobalApplicationCommandAsync(id, options); + + return model != null ? RestGlobalCommand.Create(client, model) : null; + } + + public static async Task> GetGuildApplicationCommandsAsync(BaseDiscordClient client, ulong guildId, + RequestOptions options = null) + { + var response = await client.ApiClient.GetGuildApplicationCommandsAsync(guildId, options).ConfigureAwait(false); + + if (!response.Any()) + return ImmutableArray.Create(); + + return response.Select(x => RestGuildCommand.Create(client, x, guildId)).ToImmutableArray(); + } + public static async Task GetGuildApplicationCommandAsync(BaseDiscordClient client, ulong id, ulong guildId, + RequestOptions options = null) + { + var model = await client.ApiClient.GetGuildApplicationCommandAsync(guildId, id, options); + + return model != null ? RestGuildCommand.Create(client, model, guildId) : null; + } + public static async Task CreateGuildApplicationCommandAsync(BaseDiscordClient client, ulong guildId, ApplicationCommandProperties properties, + RequestOptions options = null) + { + var model = await InteractionHelper.CreateGuildCommandAsync(client, guildId, properties, options); + + return RestGuildCommand.Create(client, model, guildId); + } + public static async Task CreateGlobalApplicationCommandAsync(BaseDiscordClient client, ApplicationCommandProperties properties, + RequestOptions options = null) + { + var model = await InteractionHelper.CreateGlobalCommandAsync(client, properties, options); + + return RestGlobalCommand.Create(client, model); + } + public static async Task> BulkOverwriteGlobalApplicationCommandAsync(BaseDiscordClient client, ApplicationCommandProperties[] properties, + RequestOptions options = null) + { + var models = await InteractionHelper.BulkOverwriteGlobalCommandsAsync(client, properties, options); + + return models.Select(x => RestGlobalCommand.Create(client, x)).ToImmutableArray(); + } + public static async Task> BulkOverwriteGuildApplicationCommandAsync(BaseDiscordClient client, ulong guildId, + ApplicationCommandProperties[] properties, RequestOptions options = null) + { + var models = await InteractionHelper.BulkOverwriteGuildCommandsAsync(client, guildId, properties, options); + + return models.Select(x => RestGuildCommand.Create(client, x, guildId)).ToImmutableArray(); + } + public static Task AddRoleAsync(BaseDiscordClient client, ulong guildId, ulong userId, ulong roleId, RequestOptions options = null) => client.ApiClient.AddRoleAsync(guildId, userId, roleId, options); + public static Task RemoveRoleAsync(BaseDiscordClient client, ulong guildId, ulong userId, ulong roleId, RequestOptions options = null) => client.ApiClient.RemoveRoleAsync(guildId, userId, roleId, options); + #endregion } } diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs index d7978db5c..abe059c64 100644 --- a/src/Discord.Net.Rest/DiscordRestApiClient.cs +++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs @@ -1,5 +1,4 @@ -#pragma warning disable CS1591 using Discord.API.Rest; using Discord.Net; using Discord.Net.Converters; @@ -24,6 +23,7 @@ namespace Discord.API { internal class DiscordRestApiClient : IDisposable { + #region DiscordRestApiClient private static readonly ConcurrentDictionary> _bucketIdGenerators = new ConcurrentDictionary>(); public event Func SentRequest { add { _sentRequestEvent.Add(value); } remove { _sentRequestEvent.Remove(value); } } @@ -45,8 +45,7 @@ internal class DiscordRestApiClient : IDisposable internal string AuthToken { get; private set; } internal IRestClient RestClient { get; private set; } internal ulong? CurrentUserId { get; set; } - internal bool UseSystemClock { get; set; } - + internal bool UseSystemClock { get; set; } internal JsonSerializer Serializer => _serializer; /// Unknown OAuth token type. @@ -57,7 +56,7 @@ public DiscordRestApiClient(RestClientProvider restClientProvider, string userAg UserAgent = userAgent; DefaultRetryMode = defaultRetryMode; _serializer = serializer ?? new JsonSerializer { ContractResolver = new DiscordContractResolver() }; - UseSystemClock = useSystemClock; + UseSystemClock = useSystemClock; RequestQueue = new RequestQueue(); _stateLock = new SemaphoreSlim(1, 1); @@ -168,15 +167,16 @@ private async Task LogoutInternalAsync() internal virtual Task ConnectInternalAsync() => Task.Delay(0); internal virtual Task DisconnectInternalAsync(Exception ex = null) => Task.Delay(0); + #endregion - //Core + #region Core internal Task SendAsync(string method, Expression> endpointExpr, BucketIds ids, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null) => SendAsync(method, GetEndpoint(endpointExpr), GetBucketId(method, ids, endpointExpr, funcName), clientBucket, options); public async Task SendAsync(string method, string endpoint, BucketId bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) { - options = options ?? new RequestOptions(); + options ??= new RequestOptions(); options.HeaderOnly = true; options.BucketId = bucketId; @@ -190,7 +190,7 @@ internal Task SendJsonAsync(string method, Expression> endpointExpr public async Task SendJsonAsync(string method, string endpoint, object payload, BucketId bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) { - options = options ?? new RequestOptions(); + options ??= new RequestOptions(); options.HeaderOnly = true; options.BucketId = bucketId; @@ -205,7 +205,7 @@ internal Task SendMultipartAsync(string method, Expression> endpoin public async Task SendMultipartAsync(string method, string endpoint, IReadOnlyDictionary multipartArgs, BucketId bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) { - options = options ?? new RequestOptions(); + options ??= new RequestOptions(); options.HeaderOnly = true; options.BucketId = bucketId; @@ -219,7 +219,7 @@ internal Task SendAsync(string method, Expression SendAsync(string method, string endpoint, BucketId bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) where TResponse : class { - options = options ?? new RequestOptions(); + options ??= new RequestOptions(); options.BucketId = bucketId; var request = new RestRequest(RestClient, method, endpoint, options); @@ -232,10 +232,11 @@ internal Task SendJsonAsync(string method, Expression SendJsonAsync(string method, string endpoint, object payload, BucketId bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) where TResponse : class { - options = options ?? new RequestOptions(); + options ??= new RequestOptions(); options.BucketId = bucketId; string json = payload != null ? SerializeJson(payload) : null; + var request = new JsonRestRequest(RestClient, method, endpoint, json, options); return DeserializeJson(await SendInternalAsync(method, endpoint, request).ConfigureAwait(false)); } @@ -246,7 +247,7 @@ internal Task SendMultipartAsync(string method, Expression public async Task SendMultipartAsync(string method, string endpoint, IReadOnlyDictionary multipartArgs, BucketId bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) { - options = options ?? new RequestOptions(); + options ??= new RequestOptions(); options.BucketId = bucketId; var request = new MultipartRestRequest(RestClient, method, endpoint, multipartArgs, options); @@ -259,8 +260,8 @@ private async Task SendInternalAsync(string method, string endpoint, Res CheckState(); if (request.Options.RetryMode == null) request.Options.RetryMode = DefaultRetryMode; - if (request.Options.UseSystemClock == null) - request.Options.UseSystemClock = UseSystemClock; + if (request.Options.UseSystemClock == null) + request.Options.UseSystemClock = UseSystemClock; var stopwatch = Stopwatch.StartNew(); var responseStream = await RequestQueue.SendAsync(request).ConfigureAwait(false); @@ -271,15 +272,17 @@ private async Task SendInternalAsync(string method, string endpoint, Res return responseStream; } + #endregion - //Auth + #region Auth public async Task ValidateTokenAsync(RequestOptions options = null) { options = RequestOptions.CreateOrClone(options); await SendAsync("GET", () => "auth/login", new BucketIds(), options: options).ConfigureAwait(false); } + #endregion - //Gateway + #region Gateway public async Task GetGatewayAsync(RequestOptions options = null) { options = RequestOptions.CreateOrClone(options); @@ -290,8 +293,9 @@ public async Task GetBotGatewayAsync(RequestOptions optio options = RequestOptions.CreateOrClone(options); return await SendAsync("GET", () => "gateway/bot", new BucketIds(), options: options).ConfigureAwait(false); } + #endregion - //Channels + #region Channels public async Task GetChannelAsync(ulong channelId, RequestOptions options = null) { Preconditions.NotEqual(channelId, 0, nameof(channelId)); @@ -316,6 +320,7 @@ public async Task GetChannelAsync(ulong guildId, ulong channelId, Reque var model = await SendAsync("GET", () => $"channels/{channelId}", ids, options: options).ConfigureAwait(false); if (!model.GuildId.IsSpecified || model.GuildId.Value != guildId) return null; + return model; } catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.NotFound) { return null; } @@ -334,11 +339,16 @@ public async Task CreateGuildChannelAsync(ulong guildId, CreateGuildCha Preconditions.NotNull(args, nameof(args)); Preconditions.GreaterThan(args.Bitrate, 0, nameof(args.Bitrate)); Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name)); + Preconditions.AtMost(args.Name.Length, 100, nameof(args.Name)); + if (args.Topic.IsSpecified) + Preconditions.AtMost(args.Topic.Value.Length, 1024, nameof(args.Name)); + options = RequestOptions.CreateOrClone(options); var ids = new BucketIds(guildId: guildId); return await SendJsonAsync("POST", () => $"guilds/{guildId}/channels", args, ids, options: options).ConfigureAwait(false); } + public async Task DeleteChannelAsync(ulong channelId, RequestOptions options = null) { Preconditions.NotEqual(channelId, 0, nameof(channelId)); @@ -362,18 +372,29 @@ public async Task ModifyGuildChannelAsync(ulong channelId, Rest.ModifyG Preconditions.NotEqual(channelId, 0, nameof(channelId)); Preconditions.NotNull(args, nameof(args)); Preconditions.AtLeast(args.Position, 0, nameof(args.Position)); - Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name)); + Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name)); + + if(args.Name.IsSpecified) + Preconditions.AtMost(args.Name.Value.Length, 100, nameof(args.Name)); + options = RequestOptions.CreateOrClone(options); var ids = new BucketIds(channelId: channelId); return await SendJsonAsync("PATCH", () => $"channels/{channelId}", args, ids, options: options).ConfigureAwait(false); } + public async Task ModifyGuildChannelAsync(ulong channelId, Rest.ModifyTextChannelParams args, RequestOptions options = null) { Preconditions.NotEqual(channelId, 0, nameof(channelId)); Preconditions.NotNull(args, nameof(args)); Preconditions.AtLeast(args.Position, 0, nameof(args.Position)); - Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name)); + Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name)); + + if(args.Name.IsSpecified) + Preconditions.AtMost(args.Name.Value.Length, 100, nameof(args.Name)); + if(args.Topic.IsSpecified) + Preconditions.AtMost(args.Topic.Value.Length, 1024, nameof(args.Name)); + Preconditions.AtLeast(args.SlowModeInterval, 0, nameof(args.SlowModeInterval)); Preconditions.AtMost(args.SlowModeInterval, 21600, nameof(args.SlowModeInterval)); options = RequestOptions.CreateOrClone(options); @@ -381,6 +402,7 @@ public async Task ModifyGuildChannelAsync(ulong channelId, Rest.ModifyT var ids = new BucketIds(channelId: channelId); return await SendJsonAsync("PATCH", () => $"channels/{channelId}", args, ids, options: options).ConfigureAwait(false); } + public async Task ModifyGuildChannelAsync(ulong channelId, Rest.ModifyVoiceChannelParams args, RequestOptions options = null) { Preconditions.NotEqual(channelId, 0, nameof(channelId)); @@ -388,12 +410,13 @@ public async Task ModifyGuildChannelAsync(ulong channelId, Rest.ModifyV Preconditions.AtLeast(args.Bitrate, 8000, nameof(args.Bitrate)); Preconditions.AtLeast(args.UserLimit, 0, nameof(args.UserLimit)); Preconditions.AtLeast(args.Position, 0, nameof(args.Position)); - Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name)); + Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name)); options = RequestOptions.CreateOrClone(options); var ids = new BucketIds(channelId: channelId); return await SendJsonAsync("PATCH", () => $"channels/{channelId}", args, ids, options: options).ConfigureAwait(false); } + public async Task ModifyGuildChannelsAsync(ulong guildId, IEnumerable args, RequestOptions options = null) { Preconditions.NotEqual(guildId, 0, nameof(guildId)); @@ -414,6 +437,266 @@ public async Task ModifyGuildChannelsAsync(ulong guildId, IEnumerable ModifyThreadAsync(ulong channelId, ModifyThreadParams args, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + + var bucket = new BucketIds(channelId: channelId); + + return await SendJsonAsync("PATCH", () => $"channels/{channelId}", args, bucket, options: options); + } + + public async Task StartThreadAsync(ulong channelId, ulong messageId, StartThreadParams args, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(messageId, 0, nameof(messageId)); + + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(0, channelId); + + return await SendJsonAsync("POST", () => $"channels/{channelId}/messages/{messageId}/threads", args, bucket, options: options).ConfigureAwait(false); + } + + public async Task StartThreadAsync(ulong channelId, StartThreadParams args, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(channelId: channelId); + + return await SendJsonAsync("POST", () => $"channels/{channelId}/threads", args, bucket, options: options).ConfigureAwait(false); + } + + public async Task JoinThreadAsync(ulong channelId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(channelId: channelId); + + await SendAsync("PUT", () => $"channels/{channelId}/thread-members/@me", bucket, options: options).ConfigureAwait(false); + } + + public async Task AddThreadMemberAsync(ulong channelId, ulong userId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(userId, 0, nameof(channelId)); + + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(channelId: channelId); + + await SendAsync("PUT", () => $"channels/{channelId}/thread-members/{userId}", bucket, options: options).ConfigureAwait(false); + } + + public async Task LeaveThreadAsync(ulong channelId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(channelId: channelId); + + await SendAsync("DELETE", () => $"channels/{channelId}/thread-members/@me", bucket, options: options).ConfigureAwait(false); + } + + public async Task RemoveThreadMemberAsync(ulong channelId, ulong userId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(userId, 0, nameof(channelId)); + + options = RequestOptions.CreateOrClone(options); + var bucket = new BucketIds(channelId: channelId); + + await SendAsync("DELETE", () => $"channels/{channelId}/thread-members/{userId}", bucket, options: options).ConfigureAwait(false); + } + + public async Task ListThreadMembersAsync(ulong channelId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(channelId: channelId); + + return await SendAsync("GET", () => $"channels/{channelId}/thread-members", bucket, options: options).ConfigureAwait(false); + } + + public async Task GetThreadMemberAsync(ulong channelId, ulong userId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(userId, 0, nameof(userId)); + + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(channelId: channelId); + + return await SendAsync("GET", () => $"channels/{channelId}/thread-members/{userId}", bucket, options: options).ConfigureAwait(false); + } + + public async Task GetActiveThreadsAsync(ulong channelId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(channelId: channelId); + + return await SendAsync("GET", () => $"channels/{channelId}/threads/active", bucket, options: options); + } + + public async Task GetPublicArchivedThreadsAsync(ulong channelId, DateTimeOffset? before = null, int? limit = null, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(channelId: channelId); + + string query = ""; + + if (limit.HasValue) + { + query = $"?before={before.GetValueOrDefault(DateTimeOffset.UtcNow).ToString("O")}&limit={limit.Value}"; + } + else if (before.HasValue) + { + query = $"?before={before.Value.ToString("O")}"; + } + + return await SendAsync("GET", () => $"channels/{channelId}/threads/archived/public{query}", bucket, options: options); + } + + public async Task GetPrivateArchivedThreadsAsync(ulong channelId, DateTimeOffset? before = null, int? limit = null, + RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(channelId: channelId); + + string query = ""; + + if (limit.HasValue) + { + query = $"?before={before.GetValueOrDefault(DateTimeOffset.UtcNow).ToString("O")}&limit={limit.Value}"; + } + else if (before.HasValue) + { + query = $"?before={before.Value.ToString("O")}"; + } + + return await SendAsync("GET", () => $"channels/{channelId}/threads/archived/private{query}", bucket, options: options); + } + + public async Task GetJoinedPrivateArchivedThreadsAsync(ulong channelId, DateTimeOffset? before = null, int? limit = null, + RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(channelId: channelId); + + string query = ""; + + if (limit.HasValue) + { + query = $"?before={SnowflakeUtils.ToSnowflake(before.GetValueOrDefault(DateTimeOffset.UtcNow))}&limit={limit.Value}"; + } + else if (before.HasValue) + { + query = $"?before={before.Value.ToString("O")}"; + } + + return await SendAsync("GET", () => $"channels/{channelId}/users/@me/threads/archived/private{query}", bucket, options: options); + } + #endregion + + #region Stage + public async Task CreateStageInstanceAsync(CreateStageInstanceParams args, RequestOptions options = null) + { + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(); + + return await SendJsonAsync("POST", () => $"stage-instances", args, bucket, options: options).ConfigureAwait(false); + } + + public async Task ModifyStageInstanceAsync(ulong channelId, ModifyStageInstanceParams args, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(channelId: channelId); + + return await SendJsonAsync("PATCH", () => $"stage-instances/{channelId}", args, bucket, options: options).ConfigureAwait(false); + } + + public async Task DeleteStageInstanceAsync(ulong channelId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + + options = RequestOptions.CreateOrClone(options); + + try + { + await SendAsync("DELETE", $"stage-instances/{channelId}", options: options).ConfigureAwait(false); + } + catch (HttpException httpEx) when (httpEx.HttpCode == HttpStatusCode.NotFound) { } + } + + public async Task GetStageInstanceAsync(ulong channelId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(channelId: channelId); + + try + { + return await SendAsync("POST", () => $"stage-instances/{channelId}", bucket, options: options).ConfigureAwait(false); + } + catch (HttpException httpEx) when (httpEx.HttpCode == HttpStatusCode.NotFound) + { + return null; + } + } + + public async Task ModifyMyVoiceState(ulong guildId, ModifyVoiceStateParams args, RequestOptions options = null) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(); + + await SendJsonAsync("PATCH", () => $"guilds/{guildId}/voice-states/@me", args, bucket, options: options).ConfigureAwait(false); + } + + public async Task ModifyUserVoiceState(ulong guildId, ulong userId, ModifyVoiceStateParams args, RequestOptions options = null) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + Preconditions.NotEqual(userId, 0, nameof(userId)); + + options = RequestOptions.CreateOrClone(options); + + var bucket = new BucketIds(); + + await SendJsonAsync("PATCH", () => $"guilds/{guildId}/voice-states/{userId}", args, bucket, options: options).ConfigureAwait(false); + } + #endregion + + #region Roles public async Task AddRoleAsync(ulong guildId, ulong userId, ulong roleId, RequestOptions options = null) { Preconditions.NotEqual(guildId, 0, nameof(guildId)); @@ -436,8 +719,9 @@ public async Task RemoveRoleAsync(ulong guildId, ulong userId, ulong roleId, Req var ids = new BucketIds(guildId: guildId); await SendAsync("DELETE", () => $"guilds/{guildId}/members/{userId}/roles/{roleId}", ids, options: options).ConfigureAwait(false); } + #endregion - //Channel Messages + #region Channel Messages public async Task GetChannelMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null) { Preconditions.NotEqual(channelId, 0, nameof(channelId)); @@ -461,22 +745,12 @@ public async Task> GetChannelMessagesAsync(ulong ch int limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxMessagesPerBatch); ulong? relativeId = args.RelativeMessageId.IsSpecified ? args.RelativeMessageId.Value : (ulong?)null; - string relativeDir; - - switch (args.RelativeDirection.GetValueOrDefault(Direction.Before)) + var relativeDir = args.RelativeDirection.GetValueOrDefault(Direction.Before) switch { - case Direction.Before: - default: - relativeDir = "before"; - break; - case Direction.After: - relativeDir = "after"; - break; - case Direction.Around: - relativeDir = "around"; - break; - } - + Direction.After => "after", + Direction.Around => "around", + _ => "before", + }; var ids = new BucketIds(channelId: channelId); Expression> endpoint; if (relativeId != null) @@ -490,7 +764,7 @@ public async Task CreateMessageAsync(ulong channelId, CreateMessagePara { Preconditions.NotNull(args, nameof(args)); Preconditions.NotEqual(channelId, 0, nameof(channelId)); - if (!args.Embed.IsSpecified || args.Embed.Value == null) + if ((!args.Embeds.IsSpecified || args.Embeds.Value == null || args.Embeds.Value.Length == 0) && (!args.Stickers.IsSpecified || args.Stickers.Value == null || args.Stickers.Value.Length == 0)) Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content)); if (args.Content?.Length > DiscordConfig.MaxMessageSize) @@ -627,189 +901,518 @@ public async Task DeleteMessagesAsync(ulong channelId, DeleteMessagesParams args break; } } - /// Message content is too long, length must be less or equal to . - public async Task ModifyMessageAsync(ulong channelId, ulong messageId, Rest.ModifyMessageParams args, RequestOptions options = null) + /// Message content is too long, length must be less or equal to . + public async Task ModifyMessageAsync(ulong channelId, ulong messageId, Rest.ModifyMessageParams args, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(messageId, 0, nameof(messageId)); + Preconditions.NotNull(args, nameof(args)); + if (args.Content.IsSpecified && args.Content.Value?.Length > DiscordConfig.MaxMessageSize) + throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content)); + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(channelId: channelId); + return await SendJsonAsync("PATCH", () => $"channels/{channelId}/messages/{messageId}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); + } + + public async Task ModifyMessageAsync(ulong channelId, ulong messageId, Rest.UploadFileParams args, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(messageId, 0, nameof(messageId)); + Preconditions.NotNull(args, nameof(args)); + if (args.Content.IsSpecified && args.Content.Value?.Length > DiscordConfig.MaxMessageSize) + throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content)); + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(channelId: channelId); + return await SendMultipartAsync("PATCH", () => $"channels/{channelId}/messages/{messageId}", args.ToDictionary(), ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); + } + #endregion + + #region Stickers, Reactions, Crosspost, and Acks + public async Task GetStickerAsync(ulong id, RequestOptions options = null) + { + Preconditions.NotEqual(id, 0, nameof(id)); + + options = RequestOptions.CreateOrClone(options); + + return await NullifyNotFound(SendAsync("GET", () => $"stickers/{id}", new BucketIds(), options: options)).ConfigureAwait(false); + } + public async Task GetGuildStickerAsync(ulong guildId, ulong id, RequestOptions options = null) + { + Preconditions.NotEqual(id, 0, nameof(id)); + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + + options = RequestOptions.CreateOrClone(options); + + return await NullifyNotFound(SendAsync("GET", () => $"guilds/{guildId}/stickers/{id}", new BucketIds(guildId), options: options)).ConfigureAwait(false); + } + public async Task ListGuildStickersAsync(ulong guildId, RequestOptions options = null) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + + options = RequestOptions.CreateOrClone(options); + + return await SendAsync("GET", () => $"guilds/{guildId}/stickers", new BucketIds(guildId), options: options).ConfigureAwait(false); + } + public async Task ListNitroStickerPacksAsync(RequestOptions options = null) + { + options = RequestOptions.CreateOrClone(options); + + return await SendAsync("GET", () => $"sticker-packs", new BucketIds(), options: options).ConfigureAwait(false); + } + public async Task CreateGuildStickerAsync(CreateStickerParams args, ulong guildId, RequestOptions options = null) + { + Preconditions.NotNull(args, nameof(args)); + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + + options = RequestOptions.CreateOrClone(options); + + return await SendMultipartAsync("POST", () => $"guilds/{guildId}/stickers", args.ToDictionary(), new BucketIds(guildId), options: options).ConfigureAwait(false); + } + public async Task ModifyStickerAsync(ModifyStickerParams args, ulong guildId, ulong stickerId, RequestOptions options = null) + { + Preconditions.NotNull(args, nameof(args)); + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + Preconditions.NotEqual(stickerId, 0, nameof(stickerId)); + + options = RequestOptions.CreateOrClone(options); + + return await SendJsonAsync("PATCH", () => $"guilds/{guildId}/stickers/{stickerId}", args, new BucketIds(guildId), options: options).ConfigureAwait(false); + } + public async Task DeleteStickerAsync(ulong guildId, ulong stickerId, RequestOptions options = null) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + Preconditions.NotEqual(stickerId, 0, nameof(stickerId)); + + options = RequestOptions.CreateOrClone(options); + + await SendAsync("DELETE", () => $"guilds/{guildId}/stickers/{stickerId}", new BucketIds(guildId), options: options).ConfigureAwait(false); + } + + public async Task AddReactionAsync(ulong channelId, ulong messageId, string emoji, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(messageId, 0, nameof(messageId)); + Preconditions.NotNullOrWhitespace(emoji, nameof(emoji)); + + options = RequestOptions.CreateOrClone(options); + options.IsReactionBucket = true; + + var ids = new BucketIds(channelId: channelId); + + // @me is non-const to fool the ratelimiter, otherwise it will put add/remove in separate buckets + var me = "@me"; + await SendAsync("PUT", () => $"channels/{channelId}/messages/{messageId}/reactions/{emoji}/{me}", ids, options: options).ConfigureAwait(false); + } + public async Task RemoveReactionAsync(ulong channelId, ulong messageId, ulong userId, string emoji, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(messageId, 0, nameof(messageId)); + Preconditions.NotNullOrWhitespace(emoji, nameof(emoji)); + + options = RequestOptions.CreateOrClone(options); + options.IsReactionBucket = true; + + var ids = new BucketIds(channelId: channelId); + + var user = CurrentUserId.HasValue ? (userId == CurrentUserId.Value ? "@me" : userId.ToString()) : userId.ToString(); + await SendAsync("DELETE", () => $"channels/{channelId}/messages/{messageId}/reactions/{emoji}/{user}", ids, options: options).ConfigureAwait(false); + } + public async Task RemoveAllReactionsAsync(ulong channelId, ulong messageId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(messageId, 0, nameof(messageId)); + + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(channelId: channelId); + + await SendAsync("DELETE", () => $"channels/{channelId}/messages/{messageId}/reactions", ids, options: options).ConfigureAwait(false); + } + public async Task RemoveAllReactionsForEmoteAsync(ulong channelId, ulong messageId, string emoji, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(messageId, 0, nameof(messageId)); + Preconditions.NotNullOrWhitespace(emoji, nameof(emoji)); + + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(channelId: channelId); + + await SendAsync("DELETE", () => $"channels/{channelId}/messages/{messageId}/reactions/{emoji}", ids, options: options).ConfigureAwait(false); + } + public async Task> GetReactionUsersAsync(ulong channelId, ulong messageId, string emoji, GetReactionUsersParams args, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(messageId, 0, nameof(messageId)); + Preconditions.NotNullOrWhitespace(emoji, nameof(emoji)); + Preconditions.NotNull(args, nameof(args)); + Preconditions.GreaterThan(args.Limit, 0, nameof(args.Limit)); + Preconditions.AtMost(args.Limit, DiscordConfig.MaxUserReactionsPerBatch, nameof(args.Limit)); + Preconditions.GreaterThan(args.AfterUserId, 0, nameof(args.AfterUserId)); + options = RequestOptions.CreateOrClone(options); + + int limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxUserReactionsPerBatch); + ulong afterUserId = args.AfterUserId.GetValueOrDefault(0); + + var ids = new BucketIds(channelId: channelId); + Expression> endpoint = () => $"channels/{channelId}/messages/{messageId}/reactions/{emoji}?limit={limit}&after={afterUserId}"; + return await SendAsync>("GET", endpoint, ids, options: options).ConfigureAwait(false); + } + public async Task AckMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(messageId, 0, nameof(messageId)); + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(channelId: channelId); + await SendAsync("POST", () => $"channels/{channelId}/messages/{messageId}/ack", ids, options: options).ConfigureAwait(false); + } + public async Task TriggerTypingIndicatorAsync(ulong channelId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(channelId: channelId); + await SendAsync("POST", () => $"channels/{channelId}/typing", ids, options: options).ConfigureAwait(false); + } + public async Task CrosspostAsync(ulong channelId, ulong messageId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(messageId, 0, nameof(messageId)); + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(channelId: channelId); + await SendAsync("POST", () => $"channels/{channelId}/messages/{messageId}/crosspost", ids, options: options).ConfigureAwait(false); + } + #endregion + + #region Channel Permissions + public async Task ModifyChannelPermissionsAsync(ulong channelId, ulong targetId, ModifyChannelPermissionsParams args, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(targetId, 0, nameof(targetId)); + Preconditions.NotNull(args, nameof(args)); + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(channelId: channelId); + await SendJsonAsync("PUT", () => $"channels/{channelId}/permissions/{targetId}", args, ids, options: options).ConfigureAwait(false); + } + public async Task DeleteChannelPermissionAsync(ulong channelId, ulong targetId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(targetId, 0, nameof(targetId)); + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(channelId: channelId); + await SendAsync("DELETE", () => $"channels/{channelId}/permissions/{targetId}", ids, options: options).ConfigureAwait(false); + } + #endregion + + #region Channel Pins + public async Task AddPinAsync(ulong channelId, ulong messageId, RequestOptions options = null) + { + Preconditions.GreaterThan(channelId, 0, nameof(channelId)); + Preconditions.GreaterThan(messageId, 0, nameof(messageId)); + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(channelId: channelId); + await SendAsync("PUT", () => $"channels/{channelId}/pins/{messageId}", ids, options: options).ConfigureAwait(false); + + } + public async Task RemovePinAsync(ulong channelId, ulong messageId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(messageId, 0, nameof(messageId)); + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(channelId: channelId); + await SendAsync("DELETE", () => $"channels/{channelId}/pins/{messageId}", ids, options: options).ConfigureAwait(false); + } + public async Task> GetPinsAsync(ulong channelId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(channelId: channelId); + return await SendAsync>("GET", () => $"channels/{channelId}/pins", ids, options: options).ConfigureAwait(false); + } + #endregion + + #region Channel Recipients + public async Task AddGroupRecipientAsync(ulong channelId, ulong userId, RequestOptions options = null) + { + Preconditions.GreaterThan(channelId, 0, nameof(channelId)); + Preconditions.GreaterThan(userId, 0, nameof(userId)); + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(channelId: channelId); + await SendAsync("PUT", () => $"channels/{channelId}/recipients/{userId}", ids, options: options).ConfigureAwait(false); + + } + public async Task RemoveGroupRecipientAsync(ulong channelId, ulong userId, RequestOptions options = null) + { + Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(userId, 0, nameof(userId)); + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(channelId: channelId); + await SendAsync("DELETE", () => $"channels/{channelId}/recipients/{userId}", ids, options: options).ConfigureAwait(false); + } + #endregion + + #region Interactions + public async Task GetGlobalApplicationCommandsAsync(RequestOptions options = null) + { + options = RequestOptions.CreateOrClone(options); + + return await SendAsync("GET", () => $"applications/{CurrentUserId}/commands", new BucketIds(), options: options).ConfigureAwait(false); + } + + public async Task GetGlobalApplicationCommandAsync(ulong id, RequestOptions options = null) + { + Preconditions.NotEqual(id, 0, nameof(id)); + + options = RequestOptions.CreateOrClone(options); + + try + { + return await SendAsync("GET", () => $"applications/{CurrentUserId}/commands/{id}", new BucketIds(), options: options).ConfigureAwait(false); + } + catch (HttpException x) when (x.HttpCode == HttpStatusCode.NotFound) { return null; } + } + + public async Task CreateGlobalApplicationCommandAsync(CreateApplicationCommandParams command, RequestOptions options = null) + { + Preconditions.NotNull(command, nameof(command)); + Preconditions.AtMost(command.Name.Length, 32, nameof(command.Name)); + Preconditions.AtLeast(command.Name.Length, 1, nameof(command.Name)); + + if (command.Type == ApplicationCommandType.Slash) + { + Preconditions.NotNullOrEmpty(command.Description, nameof(command.Description)); + Preconditions.AtMost(command.Description.Length, 100, nameof(command.Description)); + Preconditions.AtLeast(command.Description.Length, 1, nameof(command.Description)); + } + + options = RequestOptions.CreateOrClone(options); + + return await TrySendApplicationCommandAsync(SendJsonAsync("POST", () => $"applications/{CurrentUserId}/commands", command, new BucketIds(), options: options)).ConfigureAwait(false); + } + public async Task ModifyGlobalApplicationCommandAsync(ModifyApplicationCommandParams command, ulong commandId, RequestOptions options = null) + { + options = RequestOptions.CreateOrClone(options); + + return await TrySendApplicationCommandAsync(SendJsonAsync("PATCH", () => $"applications/{CurrentUserId}/commands/{commandId}", command, new BucketIds(), options: options)).ConfigureAwait(false); + } + public async Task ModifyGlobalApplicationUserCommandAsync(ModifyApplicationCommandParams command, ulong commandId, RequestOptions options = null) + { + options = RequestOptions.CreateOrClone(options); + + return await TrySendApplicationCommandAsync(SendJsonAsync("PATCH", () => $"applications/{CurrentUserId}/commands/{commandId}", command, new BucketIds(), options: options)).ConfigureAwait(false); + } + public async Task ModifyGlobalApplicationMessageCommandAsync(ModifyApplicationCommandParams command, ulong commandId, RequestOptions options = null) + { + options = RequestOptions.CreateOrClone(options); + + return await TrySendApplicationCommandAsync(SendJsonAsync("PATCH", () => $"applications/{CurrentUserId}/commands/{commandId}", command, new BucketIds(), options: options)).ConfigureAwait(false); + } + public async Task DeleteGlobalApplicationCommandAsync(ulong commandId, RequestOptions options = null) { - Preconditions.NotEqual(channelId, 0, nameof(channelId)); - Preconditions.NotEqual(messageId, 0, nameof(messageId)); - Preconditions.NotNull(args, nameof(args)); - if (args.Content.IsSpecified && args.Content.Value?.Length > DiscordConfig.MaxMessageSize) - throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content)); options = RequestOptions.CreateOrClone(options); - var ids = new BucketIds(channelId: channelId); - return await SendJsonAsync("PATCH", () => $"channels/{channelId}/messages/{messageId}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); + await SendAsync("DELETE", () => $"applications/{CurrentUserId}/commands/{commandId}", new BucketIds(), options: options).ConfigureAwait(false); } - public async Task AddReactionAsync(ulong channelId, ulong messageId, string emoji, RequestOptions options = null) + public async Task BulkOverwriteGlobalApplicationCommandsAsync(CreateApplicationCommandParams[] commands, RequestOptions options = null) { - Preconditions.NotEqual(channelId, 0, nameof(channelId)); - Preconditions.NotEqual(messageId, 0, nameof(messageId)); - Preconditions.NotNullOrWhitespace(emoji, nameof(emoji)); + options = RequestOptions.CreateOrClone(options); + return await TrySendApplicationCommandAsync(SendJsonAsync("PUT", () => $"applications/{CurrentUserId}/commands", commands, new BucketIds(), options: options)).ConfigureAwait(false); + } + + public async Task GetGuildApplicationCommandsAsync(ulong guildId, RequestOptions options = null) + { options = RequestOptions.CreateOrClone(options); - options.IsReactionBucket = true; - var ids = new BucketIds(channelId: channelId); + var bucket = new BucketIds(guildId: guildId); - // @me is non-const to fool the ratelimiter, otherwise it will put add/remove in separate buckets - var me = "@me"; - await SendAsync("PUT", () => $"channels/{channelId}/messages/{messageId}/reactions/{emoji}/{me}", ids, options: options).ConfigureAwait(false); + return await SendAsync("GET", () => $"applications/{CurrentUserId}/guilds/{guildId}/commands", bucket, options: options).ConfigureAwait(false); } - public async Task RemoveReactionAsync(ulong channelId, ulong messageId, ulong userId, string emoji, RequestOptions options = null) - { - Preconditions.NotEqual(channelId, 0, nameof(channelId)); - Preconditions.NotEqual(messageId, 0, nameof(messageId)); - Preconditions.NotNullOrWhitespace(emoji, nameof(emoji)); + public async Task GetGuildApplicationCommandAsync(ulong guildId, ulong commandId, RequestOptions options = null) + { options = RequestOptions.CreateOrClone(options); - options.IsReactionBucket = true; - var ids = new BucketIds(channelId: channelId); + var bucket = new BucketIds(guildId: guildId); - var user = CurrentUserId.HasValue ? (userId == CurrentUserId.Value ? "@me" : userId.ToString()) : userId.ToString(); - await SendAsync("DELETE", () => $"channels/{channelId}/messages/{messageId}/reactions/{emoji}/{user}", ids, options: options).ConfigureAwait(false); + try + { + return await SendAsync("GET", () => $"applications/{CurrentUserId}/guilds/{guildId}/commands/{commandId}", bucket, options: options); + } + catch (HttpException x) when (x.HttpCode == HttpStatusCode.NotFound) { return null; } } - public async Task RemoveAllReactionsAsync(ulong channelId, ulong messageId, RequestOptions options = null) + + public async Task CreateGuildApplicationCommandAsync(CreateApplicationCommandParams command, ulong guildId, RequestOptions options = null) { - Preconditions.NotEqual(channelId, 0, nameof(channelId)); - Preconditions.NotEqual(messageId, 0, nameof(messageId)); + Preconditions.NotNull(command, nameof(command)); + Preconditions.AtMost(command.Name.Length, 32, nameof(command.Name)); + Preconditions.AtLeast(command.Name.Length, 1, nameof(command.Name)); + + if (command.Type == ApplicationCommandType.Slash) + { + Preconditions.NotNullOrEmpty(command.Description, nameof(command.Description)); + Preconditions.AtMost(command.Description.Length, 100, nameof(command.Description)); + Preconditions.AtLeast(command.Description.Length, 1, nameof(command.Description)); + } options = RequestOptions.CreateOrClone(options); - var ids = new BucketIds(channelId: channelId); + var bucket = new BucketIds(guildId: guildId); - await SendAsync("DELETE", () => $"channels/{channelId}/messages/{messageId}/reactions", ids, options: options).ConfigureAwait(false); + return await TrySendApplicationCommandAsync(SendJsonAsync("POST", () => $"applications/{CurrentUserId}/guilds/{guildId}/commands", command, bucket, options: options)).ConfigureAwait(false); } - public async Task RemoveAllReactionsForEmoteAsync(ulong channelId, ulong messageId, string emoji, RequestOptions options = null) + public async Task ModifyGuildApplicationCommandAsync(ModifyApplicationCommandParams command, ulong guildId, ulong commandId, RequestOptions options = null) { - Preconditions.NotEqual(channelId, 0, nameof(channelId)); - Preconditions.NotEqual(messageId, 0, nameof(messageId)); - Preconditions.NotNullOrWhitespace(emoji, nameof(emoji)); - options = RequestOptions.CreateOrClone(options); - var ids = new BucketIds(channelId: channelId); + var bucket = new BucketIds(guildId: guildId); - await SendAsync("DELETE", () => $"channels/{channelId}/messages/{messageId}/reactions/{emoji}", ids, options: options).ConfigureAwait(false); + return await TrySendApplicationCommandAsync(SendJsonAsync("PATCH", () => $"applications/{CurrentUserId}/guilds/{guildId}/commands/{commandId}", command, bucket, options: options)).ConfigureAwait(false); } - public async Task> GetReactionUsersAsync(ulong channelId, ulong messageId, string emoji, GetReactionUsersParams args, RequestOptions options = null) + public async Task DeleteGuildApplicationCommandAsync(ulong guildId, ulong commandId, RequestOptions options = null) { - Preconditions.NotEqual(channelId, 0, nameof(channelId)); - Preconditions.NotEqual(messageId, 0, nameof(messageId)); - Preconditions.NotNullOrWhitespace(emoji, nameof(emoji)); - Preconditions.NotNull(args, nameof(args)); - Preconditions.GreaterThan(args.Limit, 0, nameof(args.Limit)); - Preconditions.AtMost(args.Limit, DiscordConfig.MaxUserReactionsPerBatch, nameof(args.Limit)); - Preconditions.GreaterThan(args.AfterUserId, 0, nameof(args.AfterUserId)); options = RequestOptions.CreateOrClone(options); - int limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxUserReactionsPerBatch); - ulong afterUserId = args.AfterUserId.GetValueOrDefault(0); + var bucket = new BucketIds(guildId: guildId); - var ids = new BucketIds(channelId: channelId); - Expression> endpoint = () => $"channels/{channelId}/messages/{messageId}/reactions/{emoji}?limit={limit}&after={afterUserId}"; - return await SendAsync>("GET", endpoint, ids, options: options).ConfigureAwait(false); + await SendAsync("DELETE", () => $"applications/{CurrentUserId}/guilds/{guildId}/commands/{commandId}", bucket, options: options).ConfigureAwait(false); } - public async Task AckMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null) + + public async Task BulkOverwriteGuildApplicationCommandsAsync(ulong guildId, CreateApplicationCommandParams[] commands, RequestOptions options = null) { - Preconditions.NotEqual(channelId, 0, nameof(channelId)); - Preconditions.NotEqual(messageId, 0, nameof(messageId)); options = RequestOptions.CreateOrClone(options); - var ids = new BucketIds(channelId: channelId); - await SendAsync("POST", () => $"channels/{channelId}/messages/{messageId}/ack", ids, options: options).ConfigureAwait(false); + var bucket = new BucketIds(guildId: guildId); + + return await TrySendApplicationCommandAsync(SendJsonAsync("PUT", () => $"applications/{CurrentUserId}/guilds/{guildId}/commands", commands, bucket, options: options)).ConfigureAwait(false); } - public async Task TriggerTypingIndicatorAsync(ulong channelId, RequestOptions options = null) + #endregion + + #region Interaction Responses + public async Task CreateInteractionResponseAsync(InteractionResponse response, ulong interactionId, string interactionToken, RequestOptions options = null) { - Preconditions.NotEqual(channelId, 0, nameof(channelId)); + if (response.Data.IsSpecified && response.Data.Value.Content.IsSpecified) + Preconditions.AtMost(response.Data.Value.Content.Value?.Length ?? 0, 2000, nameof(response.Data.Value.Content)); + options = RequestOptions.CreateOrClone(options); - var ids = new BucketIds(channelId: channelId); - await SendAsync("POST", () => $"channels/{channelId}/typing", ids, options: options).ConfigureAwait(false); + await SendJsonAsync("POST", () => $"interactions/{interactionId}/{interactionToken}/callback", response, new BucketIds(), options: options); } - public async Task CrosspostAsync(ulong channelId, ulong messageId, RequestOptions options = null) + public async Task GetInteractionResponseAsync(string interactionToken, RequestOptions options = null) { - Preconditions.NotEqual(channelId, 0, nameof(channelId)); - Preconditions.NotEqual(messageId, 0, nameof(messageId)); + Preconditions.NotNullOrEmpty(interactionToken, nameof(interactionToken)); + options = RequestOptions.CreateOrClone(options); - var ids = new BucketIds(channelId: channelId); - await SendAsync("POST", () => $"channels/{channelId}/messages/{messageId}/crosspost", ids, options: options).ConfigureAwait(false); + return await SendAsync("GET", () => $"webhooks/{CurrentUserId}/{interactionToken}/messages/@original", new BucketIds(), options: options).ConfigureAwait(false); } - - //Channel Permissions - public async Task ModifyChannelPermissionsAsync(ulong channelId, ulong targetId, ModifyChannelPermissionsParams args, RequestOptions options = null) + public async Task ModifyInteractionResponseAsync(ModifyInteractionResponseParams args, string interactionToken, RequestOptions options = null) { - Preconditions.NotEqual(channelId, 0, nameof(channelId)); - Preconditions.NotEqual(targetId, 0, nameof(targetId)); - Preconditions.NotNull(args, nameof(args)); options = RequestOptions.CreateOrClone(options); - var ids = new BucketIds(channelId: channelId); - await SendJsonAsync("PUT", () => $"channels/{channelId}/permissions/{targetId}", args, ids, options: options).ConfigureAwait(false); + return await SendJsonAsync("PATCH", () => $"webhooks/{CurrentUserId}/{interactionToken}/messages/@original", args, new BucketIds(), options: options); } - public async Task DeleteChannelPermissionAsync(ulong channelId, ulong targetId, RequestOptions options = null) + public async Task DeleteInteractionResponseAsync(string interactionToken, RequestOptions options = null) { - Preconditions.NotEqual(channelId, 0, nameof(channelId)); - Preconditions.NotEqual(targetId, 0, nameof(targetId)); options = RequestOptions.CreateOrClone(options); - var ids = new BucketIds(channelId: channelId); - await SendAsync("DELETE", () => $"channels/{channelId}/permissions/{targetId}", ids, options: options).ConfigureAwait(false); + await SendAsync("DELETE", () => $"webhooks/{CurrentUserId}/{interactionToken}/messages/@original", new BucketIds(), options: options); } - //Channel Pins - public async Task AddPinAsync(ulong channelId, ulong messageId, RequestOptions options = null) + public async Task CreateInteractionFollowupMessageAsync(CreateWebhookMessageParams args, string token, RequestOptions options = null) { - Preconditions.GreaterThan(channelId, 0, nameof(channelId)); - Preconditions.GreaterThan(messageId, 0, nameof(messageId)); + if ((!args.Embeds.IsSpecified || args.Embeds.Value == null || args.Embeds.Value.Length == 0) && !args.File.IsSpecified) + Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content)); + + if (args.Content?.Length > DiscordConfig.MaxMessageSize) + throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content)); + options = RequestOptions.CreateOrClone(options); - var ids = new BucketIds(channelId: channelId); - await SendAsync("PUT", () => $"channels/{channelId}/pins/{messageId}", ids, options: options).ConfigureAwait(false); + if (!args.File.IsSpecified) + return await SendJsonAsync("POST", () => $"webhooks/{CurrentUserId}/{token}?wait=true", args, new BucketIds(), options: options).ConfigureAwait(false); + else + return await SendMultipartAsync("POST", () => $"webhooks/{CurrentUserId}/{token}?wait=true", args.ToDictionary(), new BucketIds(), options: options).ConfigureAwait(false); + } + + public async Task ModifyInteractionFollowupMessageAsync(ModifyInteractionResponseParams args, ulong id, string token, RequestOptions options = null) + { + Preconditions.NotNull(args, nameof(args)); + Preconditions.NotEqual(id, 0, nameof(id)); + if (args.Content.IsSpecified) + if (args.Content.Value.Length > DiscordConfig.MaxMessageSize) + throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content)); + + options = RequestOptions.CreateOrClone(options); + + return await SendJsonAsync("PATCH", () => $"webhooks/{CurrentUserId}/{token}/messages/{id}", args, new BucketIds(), options: options).ConfigureAwait(false); } - public async Task RemovePinAsync(ulong channelId, ulong messageId, RequestOptions options = null) + + public async Task DeleteInteractionFollowupMessageAsync(ulong id, string token, RequestOptions options = null) { - Preconditions.NotEqual(channelId, 0, nameof(channelId)); - Preconditions.NotEqual(messageId, 0, nameof(messageId)); + Preconditions.NotEqual(id, 0, nameof(id)); + options = RequestOptions.CreateOrClone(options); - var ids = new BucketIds(channelId: channelId); - await SendAsync("DELETE", () => $"channels/{channelId}/pins/{messageId}", ids, options: options).ConfigureAwait(false); + await SendAsync("DELETE", () => $"webhooks/{CurrentUserId}/{token}/messages/{id}", new BucketIds(), options: options).ConfigureAwait(false); } - public async Task> GetPinsAsync(ulong channelId, RequestOptions options = null) + #endregion + + #region Application Command permissions + public async Task GetGuildApplicationCommandPermissionsAsync(ulong guildId, RequestOptions options = null) { - Preconditions.NotEqual(channelId, 0, nameof(channelId)); + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + options = RequestOptions.CreateOrClone(options); - var ids = new BucketIds(channelId: channelId); - return await SendAsync>("GET", () => $"channels/{channelId}/pins", ids, options: options).ConfigureAwait(false); + return await SendAsync("GET", () => $"applications/{CurrentUserId}/guilds/{guildId}/commands/permissions", new BucketIds(), options: options).ConfigureAwait(false); } - //Channel Recipients - public async Task AddGroupRecipientAsync(ulong channelId, ulong userId, RequestOptions options = null) + public async Task GetGuildApplicationCommandPermissionAsync(ulong guildId, ulong commandId, RequestOptions options = null) { - Preconditions.GreaterThan(channelId, 0, nameof(channelId)); - Preconditions.GreaterThan(userId, 0, nameof(userId)); + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + Preconditions.NotEqual(commandId, 0, nameof(commandId)); + options = RequestOptions.CreateOrClone(options); - var ids = new BucketIds(channelId: channelId); - await SendAsync("PUT", () => $"channels/{channelId}/recipients/{userId}", ids, options: options).ConfigureAwait(false); + return await SendAsync("GET", () => $"applications/{CurrentUserId}/guilds/{guildId}/commands/{commandId}/permissions", new BucketIds(), options: options).ConfigureAwait(false); + } + + public async Task ModifyApplicationCommandPermissionsAsync(ModifyGuildApplicationCommandPermissionsParams permissions, ulong guildId, ulong commandId, RequestOptions options = null) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + Preconditions.NotEqual(commandId, 0, nameof(commandId)); + options = RequestOptions.CreateOrClone(options); + + return await SendJsonAsync("PUT", () => $"applications/{CurrentUserId}/guilds/{guildId}/commands/{commandId}/permissions", permissions, new BucketIds(), options: options).ConfigureAwait(false); } - public async Task RemoveGroupRecipientAsync(ulong channelId, ulong userId, RequestOptions options = null) + + public async Task> BatchModifyApplicationCommandPermissionsAsync(ModifyGuildApplicationCommandPermissions[] permissions, ulong guildId, RequestOptions options = null) { - Preconditions.NotEqual(channelId, 0, nameof(channelId)); - Preconditions.NotEqual(userId, 0, nameof(userId)); + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + Preconditions.NotNull(permissions, nameof(permissions)); + options = RequestOptions.CreateOrClone(options); - var ids = new BucketIds(channelId: channelId); - await SendAsync("DELETE", () => $"channels/{channelId}/recipients/{userId}", ids, options: options).ConfigureAwait(false); + return await SendJsonAsync("PUT", () => $"applications/{CurrentUserId}/guilds/{guildId}/commands/permissions", permissions, new BucketIds(), options: options).ConfigureAwait(false); } + #endregion - //Guilds + #region Guilds public async Task GetGuildAsync(ulong guildId, bool withCounts, RequestOptions options = null) { Preconditions.NotEqual(guildId, 0, nameof(guildId)); @@ -882,8 +1485,9 @@ public async Task GetGuildPruneCountAsync(ulong guil var ids = new BucketIds(guildId: guildId); return await SendAsync("GET", () => $"guilds/{guildId}/prune?days={args.Days}{endpointRoleIds}", ids, options: options).ConfigureAwait(false); } + #endregion - //Guild Bans + #region Guild Bans public async Task> GetGuildBansAsync(ulong guildId, RequestOptions options = null) { Preconditions.NotEqual(guildId, 0, nameof(guildId)); @@ -934,8 +1538,9 @@ public async Task RemoveGuildBanAsync(ulong guildId, ulong userId, RequestOption var ids = new BucketIds(guildId: guildId); await SendAsync("DELETE", () => $"guilds/{guildId}/bans/{userId}", ids, options: options).ConfigureAwait(false); } + #endregion - //Guild Widget + #region Guild Widget /// must not be equal to zero. public async Task GetGuildWidgetAsync(ulong guildId, RequestOptions options = null) { @@ -960,8 +1565,9 @@ public async Task ModifyGuildWidgetAsync(ulong guildId, Rest.Modify var ids = new BucketIds(guildId: guildId); return await SendJsonAsync("PATCH", () => $"guilds/{guildId}/widget", args, ids, options: options).ConfigureAwait(false); } + #endregion - //Guild Integrations + #region Guild Integrations /// must not be equal to zero. public async Task> GetGuildIntegrationsAsync(ulong guildId, RequestOptions options = null) { @@ -1013,8 +1619,9 @@ public async Task SyncGuildIntegrationAsync(ulong guildId, ulong in var ids = new BucketIds(guildId: guildId); return await SendAsync("POST", () => $"guilds/{guildId}/integrations/{integrationId}/sync", ids, options: options).ConfigureAwait(false); } + #endregion - //Guild Invites + #region Guild Invites /// cannot be blank. /// must not be . public async Task GetInviteAsync(string inviteId, RequestOptions options = null) @@ -1079,6 +1686,12 @@ public async Task CreateChannelInviteAsync(ulong channelId, Crea Preconditions.AtLeast(args.MaxUses, 0, nameof(args.MaxUses)); Preconditions.AtMost(args.MaxAge, 86400, nameof(args.MaxAge), "The maximum age of an invite must be less than or equal to a day (86400 seconds)."); + if (args.TargetType.IsSpecified) + { + Preconditions.NotEqual((int)args.TargetType.Value, (int)TargetUserType.Undefined, nameof(args.TargetType)); + if (args.TargetType.Value == TargetUserType.Stream) Preconditions.GreaterThan(args.TargetUserId, 0, nameof(args.TargetUserId)); + if (args.TargetType.Value == TargetUserType.EmbeddedApplication) Preconditions.GreaterThan(args.TargetApplicationId, 0, nameof(args.TargetUserId)); + } options = RequestOptions.CreateOrClone(options); var ids = new BucketIds(channelId: channelId); @@ -1091,8 +1704,9 @@ public async Task DeleteInviteAsync(string inviteId, RequestOptions opti return await SendAsync("DELETE", () => $"invites/{inviteId}", new BucketIds(), options: options).ConfigureAwait(false); } + #endregion - //Guild Members + #region Guild Members public async Task AddGuildMemberAsync(ulong guildId, ulong userId, AddGuildMemberParams args, RequestOptions options = null) { Preconditions.NotEqual(guildId, 0, nameof(guildId)); @@ -1190,8 +1804,9 @@ public async Task> SearchGuildMembersAsync(ulon Expression> endpoint = () => $"guilds/{guildId}/members/search?limit={limit}&query={query}"; return await SendAsync>("GET", endpoint, ids, options: options).ConfigureAwait(false); } + #endregion - //Guild Roles + #region Guild Roles public async Task> GetGuildRolesAsync(ulong guildId, RequestOptions options = null) { Preconditions.NotEqual(guildId, 0, nameof(guildId)); @@ -1238,8 +1853,9 @@ public async Task> ModifyGuildRolesAsync(ulong guildId var ids = new BucketIds(guildId: guildId); return await SendJsonAsync>("PATCH", () => $"guilds/{guildId}/roles", args, ids, options: options).ConfigureAwait(false); } + #endregion - //Guild emoji + #region Guild emoji public async Task> GetGuildEmotesAsync(ulong guildId, RequestOptions options = null) { Preconditions.NotEqual(guildId, 0, nameof(guildId)); @@ -1291,8 +1907,108 @@ public async Task DeleteGuildEmoteAsync(ulong guildId, ulong emoteId, RequestOpt var ids = new BucketIds(guildId: guildId); await SendAsync("DELETE", () => $"guilds/{guildId}/emojis/{emoteId}", ids, options: options).ConfigureAwait(false); } + #endregion + + #region Guild Events + + public async Task ListGuildScheduledEventsAsync(ulong guildId, RequestOptions options = null) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(guildId: guildId); + return await SendAsync("GET", () => $"guilds/{guildId}/scheduled-events?with_user_count=true", ids, options: options).ConfigureAwait(false); + } + + public async Task GetGuildScheduledEventAsync(ulong eventId, ulong guildId, RequestOptions options = null) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + Preconditions.NotEqual(eventId, 0, nameof(eventId)); + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(guildId: guildId); + + return await NullifyNotFound(SendAsync("GET", () => $"guilds/{guildId}/scheduled-events/{eventId}?with_user_count=true", ids, options: options)).ConfigureAwait(false); + } + + public async Task CreateGuildScheduledEventAsync(CreateGuildScheduledEventParams args, ulong guildId, RequestOptions options = null) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + Preconditions.NotNull(args, nameof(args)); + + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(guildId: guildId); + + return await SendJsonAsync("POST", () => $"guilds/{guildId}/scheduled-events", args, ids, options: options).ConfigureAwait(false); + } + + public async Task ModifyGuildScheduledEventAsync(ModifyGuildScheduledEventParams args, ulong eventId, ulong guildId, RequestOptions options = null) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + Preconditions.NotEqual(eventId, 0, nameof(eventId)); + Preconditions.NotNull(args, nameof(args)); + + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(guildId: guildId); + + return await SendJsonAsync("PATCH", () => $"guilds/{guildId}/scheduled-events/{eventId}", args, ids, options: options).ConfigureAwait(false); + } + + public async Task DeleteGuildScheduledEventAsync(ulong eventId, ulong guildId, RequestOptions options = null) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + Preconditions.NotEqual(eventId, 0, nameof(eventId)); + + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(guildId: guildId); + + await SendAsync("DELETE", () => $"guilds/{guildId}/scheduled-events/{eventId}", ids, options: options).ConfigureAwait(false); + } + + public async Task GetGuildScheduledEventUsersAsync(ulong eventId, ulong guildId, int limit = 100, RequestOptions options = null) + { + Preconditions.NotEqual(guildId, 0, nameof(guildId)); + Preconditions.NotEqual(eventId, 0, nameof(eventId)); + + options = RequestOptions.CreateOrClone(options); + + var ids = new BucketIds(guildId: guildId); + + return await SendAsync("GET", () => $"guilds/{guildId}/scheduled-events/{eventId}/users?limit={limit}&with_member=true", ids, options: options).ConfigureAwait(false); + } + + public async Task GetGuildScheduledEventUsersAsync(ulong eventId, ulong guildId, GetEventUsersParams args, RequestOptions options = null) + { + Preconditions.NotEqual(eventId, 0, nameof(eventId)); + Preconditions.NotNull(args, nameof(args)); + Preconditions.AtLeast(args.Limit, 0, nameof(args.Limit)); + Preconditions.AtMost(args.Limit, DiscordConfig.MaxMessagesPerBatch, nameof(args.Limit)); + options = RequestOptions.CreateOrClone(options); + + int limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxGuildEventUsersPerBatch); + ulong? relativeId = args.RelativeUserId.IsSpecified ? args.RelativeUserId.Value : (ulong?)null; + var relativeDir = args.RelativeDirection.GetValueOrDefault(Direction.Before) switch + { + Direction.After => "after", + Direction.Around => "around", + _ => "before", + }; + var ids = new BucketIds(guildId: guildId); + Expression> endpoint; + if (relativeId != null) + endpoint = () => $"guilds/{guildId}/scheduled-events/{eventId}/users?with_member=true&limit={limit}&{relativeDir}={relativeId}"; + else + endpoint = () => $"guilds/{guildId}/scheduled-events/{eventId}/users?with_member=true&limit={limit}"; + + return await SendAsync("GET", endpoint, ids, options: options).ConfigureAwait(false); + } + + #endregion - //Users + #region Users public async Task GetUserAsync(ulong userId, RequestOptions options = null) { Preconditions.NotEqual(userId, 0, nameof(userId)); @@ -1304,8 +2020,9 @@ public async Task GetUserAsync(ulong userId, RequestOptions options = null } catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.NotFound) { return null; } } + #endregion - //Current User/DMs + #region Current User/DMs public async Task GetMyUserAsync(RequestOptions options = null) { options = RequestOptions.CreateOrClone(options); @@ -1364,8 +2081,9 @@ public async Task CreateDMChannelAsync(CreateDMChannelParams args, Requ return await SendJsonAsync("POST", () => "users/@me/channels", args, new BucketIds(), options: options).ConfigureAwait(false); } + #endregion - //Voice Regions + #region Voice Regions public async Task> GetVoiceRegionsAsync(RequestOptions options = null) { options = RequestOptions.CreateOrClone(options); @@ -1379,8 +2097,9 @@ public async Task> GetGuildVoiceRegionsAsync(ul var ids = new BucketIds(guildId: guildId); return await SendAsync>("GET", () => $"guilds/{guildId}/regions", ids, options: options).ConfigureAwait(false); } + #endregion - //Audit logs + #region Audit logs public async Task GetAuditLogsAsync(ulong guildId, GetAuditLogsParams args, RequestOptions options = null) { Preconditions.NotEqual(guildId, 0, nameof(guildId)); @@ -1409,12 +2128,13 @@ public async Task GetAuditLogsAsync(ulong guildId, GetAuditLogsParams .Append(args.ActionType.Value); } - // still use string interp for the query w/o params, as this is necessary for CreateBucketId + // Still use string interp for the query w/o params, as this is necessary for CreateBucketId endpoint = () => $"guilds/{guildId}/audit-logs?limit={limit}{queryArgs.ToString()}"; return await SendAsync("GET", endpoint, ids, options: options).ConfigureAwait(false); } + #endregion - //Webhooks + #region Webhooks public async Task CreateWebhookAsync(ulong channelId, CreateWebhookParams args, RequestOptions options = null) { Preconditions.NotEqual(channelId, 0, nameof(channelId)); @@ -1477,8 +2197,9 @@ public async Task> GetChannelWebhooksAsync(ulong ch var ids = new BucketIds(channelId: channelId); return await SendAsync>("GET", () => $"channels/{channelId}/webhooks", ids, options: options).ConfigureAwait(false); } + #endregion - //Helpers + #region Helpers /// Client is not logged in. protected void CheckState() { @@ -1501,6 +2222,66 @@ protected T DeserializeJson(Stream jsonStream) return _serializer.Deserialize(reader); } + protected async Task TrySendApplicationCommandAsync(Task sendTask) + { + try + { + var result = await sendTask.ConfigureAwait(false); + + if (sendTask.Exception != null) + { + if (sendTask.Exception.InnerException is HttpException x) + { + if (x.HttpCode == HttpStatusCode.BadRequest) + { + var json = (x.Request as JsonRestRequest).Json; + throw new ApplicationCommandException(x); + } + } + + throw sendTask.Exception; + } + else + return result; + } + catch (HttpException x) + { + if (x.HttpCode == HttpStatusCode.BadRequest) + { + var json = (x.Request as JsonRestRequest).Json; + throw new ApplicationCommandException(x); + } + + throw; + } + } + + protected async Task NullifyNotFound(Task sendTask) where T : class + { + try + { + var result = await sendTask.ConfigureAwait(false); + + if (sendTask.Exception != null) + { + if (sendTask.Exception.InnerException is HttpException x) + { + if (x.HttpCode == HttpStatusCode.NotFound) + { + return null; + } + } + + throw sendTask.Exception; + } + else + return result; + } + catch (HttpException x) when (x.HttpCode == HttpStatusCode.NotFound) + { + return null; + } + } internal class BucketIds { public ulong GuildId { get; internal set; } @@ -1532,15 +2313,14 @@ internal Dictionary ToMajorParametersDictionary() internal static int? GetIndex(string name) { - switch (name) + return name switch { - case "httpMethod": return 0; - case "guildId": return 1; - case "channelId": return 2; - case "webhookId": return 3; - default: - return null; - } + "httpMethod" => 0, + "guildId" => 1, + "channelId" => 2, + "webhookId" => 3, + _ => null, + }; } } @@ -1576,7 +2356,7 @@ private static Func CreateBucketId(Expression> Array.Copy(elements, 0, methodArgs, 1, elements.Length); } - int endIndex = format.IndexOf('?'); //Dont include params + int endIndex = format.IndexOf('?'); //Don't include params if (endIndex == -1) endIndex = format.Length; @@ -1628,5 +2408,6 @@ private static string GetFieldName(Expression expr) return (expr as MemberExpression).Member.Name; } + #endregion } } diff --git a/src/Discord.Net.Rest/DiscordRestClient.cs b/src/Discord.Net.Rest/DiscordRestClient.cs index b5bdc4235..93183161b 100644 --- a/src/Discord.Net.Rest/DiscordRestClient.cs +++ b/src/Discord.Net.Rest/DiscordRestClient.cs @@ -1,7 +1,13 @@ +//using Discord.Rest.Entities.Interactions; +using Discord.Net; +using Discord.Net.Converters; +using Discord.Net.ED25519; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; +using System.Text; using System.Threading.Tasks; namespace Discord.Rest @@ -11,13 +17,15 @@ namespace Discord.Rest /// public class DiscordRestClient : BaseDiscordClient, IDiscordClient { + #region DiscordRestClient private RestApplication _applicationInfo; + internal static JsonSerializer Serializer = new JsonSerializer() { ContractResolver = new DiscordContractResolver(), NullValueHandling = NullValueHandling.Include }; /// /// Gets the logged-in user. /// public new RestSelfUser CurrentUser { get => base.CurrentUser as RestSelfUser; internal set => base.CurrentUser = value; } - + /// public DiscordRestClient() : this(new DiscordRestConfig()) { } /// @@ -29,7 +37,7 @@ public DiscordRestClient(DiscordRestConfig config) : base(config, CreateApiClien internal DiscordRestClient(DiscordRestConfig config, API.DiscordRestApiClient api) : base(config, api) { } private static API.DiscordRestApiClient CreateApiClient(DiscordRestConfig config) - => new API.DiscordRestApiClient(config.RestClientProvider, DiscordRestConfig.UserAgent, useSystemClock: config.UseSystemClock); + => new API.DiscordRestApiClient(config.RestClientProvider, DiscordRestConfig.UserAgent, serializer: Serializer, useSystemClock: config.UseSystemClock); internal override void Dispose(bool disposing) { @@ -46,6 +54,11 @@ internal override async Task OnLoginAsync(TokenType tokenType, string token) ApiClient.CurrentUserId = user.Id; base.CurrentUser = RestSelfUser.Create(this, user); } + + internal void CreateRestSelfUser(API.User user) + { + base.CurrentUser = RestSelfUser.Create(this, user); + } /// internal override Task OnLogoutAsync() { @@ -53,9 +66,73 @@ internal override Task OnLogoutAsync() return Task.Delay(0); } + #region Rest interactions + + public bool IsValidHttpInteraction(string publicKey, string signature, string timestamp, string body) + => IsValidHttpInteraction(publicKey, signature, timestamp, Encoding.UTF8.GetBytes(body)); + public bool IsValidHttpInteraction(string publicKey, string signature, string timestamp, byte[] body) + { + var key = HexConverter.HexToByteArray(publicKey); + var sig = HexConverter.HexToByteArray(signature); + var tsp = Encoding.UTF8.GetBytes(timestamp); + + var message = new List(); + message.AddRange(tsp); + message.AddRange(body); + + return IsValidHttpInteraction(key, sig, message.ToArray()); + } + + private bool IsValidHttpInteraction(byte[] publicKey, byte[] signature, byte[] message) + { + return Ed25519.Verify(signature, message, publicKey); + } + + /// + /// Creates a from a http message. + /// + /// The public key of your application + /// The signature sent with the interaction. + /// The timestamp sent with the interaction. + /// The body of the http message. + /// + /// A that represents the incoming http interaction. + /// + /// Thrown when the signature doesn't match the public key. + public Task ParseHttpInteractionAsync(string publicKey, string signature, string timestamp, string body) + => ParseHttpInteractionAsync(publicKey, signature, timestamp, Encoding.UTF8.GetBytes(body)); + + /// + /// Creates a from a http message. + /// + /// The public key of your application + /// The signature sent with the interaction. + /// The timestamp sent with the interaction. + /// The body of the http message. + /// + /// A that represents the incoming http interaction. + /// + /// Thrown when the signature doesn't match the public key. + public async Task ParseHttpInteractionAsync(string publicKey, string signature, string timestamp, byte[] body) + { + if (!IsValidHttpInteraction(publicKey, signature, timestamp, body)) + { + throw new BadSignatureException(); + } + + using (var textReader = new StringReader(Encoding.UTF8.GetString(body))) + using (var jsonReader = new JsonTextReader(textReader)) + { + var model = Serializer.Deserialize(jsonReader); + return await RestInteraction.CreateAsync(this, model); + } + } + + #endregion + public async Task GetApplicationInfoAsync(RequestOptions options = null) { - return _applicationInfo ?? (_applicationInfo = await ClientHelper.GetApplicationInfoAsync(this, options).ConfigureAwait(false)); + return _applicationInfo ??= await ClientHelper.GetApplicationInfoAsync(this, options).ConfigureAwait(false); } public Task GetChannelAsync(ulong id, RequestOptions options = null) @@ -101,6 +178,24 @@ public Task GetVoiceRegionAsync(string id, RequestOptions optio => ClientHelper.GetVoiceRegionAsync(this, id, options); public Task GetWebhookAsync(ulong id, RequestOptions options = null) => ClientHelper.GetWebhookAsync(this, id, options); + + public Task CreateGlobalCommand(ApplicationCommandProperties properties, RequestOptions options = null) + => ClientHelper.CreateGlobalApplicationCommandAsync(this, properties, options); + public Task CreateGuildCommand(ApplicationCommandProperties properties, ulong guildId, RequestOptions options = null) + => ClientHelper.CreateGuildApplicationCommandAsync(this, guildId, properties, options); + public Task> GetGlobalApplicationCommands(RequestOptions options = null) + => ClientHelper.GetGlobalApplicationCommandsAsync(this, options); + public Task> GetGuildApplicationCommands(ulong guildId, RequestOptions options = null) + => ClientHelper.GetGuildApplicationCommandsAsync(this, guildId, options); + public Task> BulkOverwriteGlobalCommands(ApplicationCommandProperties[] commandProperties, RequestOptions options = null) + => ClientHelper.BulkOverwriteGlobalApplicationCommandAsync(this, commandProperties, options); + public Task> BulkOverwriteGuildCommands(ApplicationCommandProperties[] commandProperties, ulong guildId, RequestOptions options = null) + => ClientHelper.BulkOverwriteGuildApplicationCommandAsync(this, guildId, commandProperties, options); + public Task> BatchEditGuildCommandPermissions(ulong guildId, IDictionary permissions, RequestOptions options = null) + => InteractionHelper.BatchEditGuildCommandPermissionsAsync(this, guildId, permissions, options); + public Task DeleteAllGlobalCommandsAsync(RequestOptions options = null) + => InteractionHelper.DeleteAllGlobalCommandsAsync(this, options); + public Task AddRoleAsync(ulong guildId, ulong userId, ulong roleId) => ClientHelper.AddRoleAsync(this, guildId, userId, roleId); public Task RemoveRoleAsync(ulong guildId, ulong userId, ulong roleId) @@ -114,7 +209,9 @@ public Task RemoveAllReactionsAsync(ulong channelId, ulong messageId, RequestOpt => MessageHelper.RemoveAllReactionsAsync(channelId, messageId, this, options); public Task RemoveAllReactionsForEmoteAsync(ulong channelId, ulong messageId, IEmote emote, RequestOptions options = null) => MessageHelper.RemoveAllReactionsForEmoteAsync(channelId, messageId, emote, this, options); - //IDiscordClient +#endregion + + #region IDiscordClient /// async Task IDiscordClient.GetApplicationInfoAsync(RequestOptions options) => await GetApplicationInfoAsync(options).ConfigureAwait(false); @@ -198,5 +295,13 @@ async Task IDiscordClient.GetVoiceRegionAsync(string id, RequestOp /// async Task IDiscordClient.GetWebhookAsync(ulong id, RequestOptions options) => await GetWebhookAsync(id, options).ConfigureAwait(false); + + /// + async Task> IDiscordClient.GetGlobalApplicationCommandsAsync(RequestOptions options) + => await GetGlobalApplicationCommands(options).ConfigureAwait(false); + /// + async Task IDiscordClient.GetGlobalApplicationCommandAsync(ulong id, RequestOptions options) + => await ClientHelper.GetGlobalApplicationCommandAsync(this, id, options).ConfigureAwait(false); + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/AuditLogHelper.cs b/src/Discord.Net.Rest/Entities/AuditLogs/AuditLogHelper.cs index 696917203..b3aaf582c 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/AuditLogHelper.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/AuditLogHelper.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Model = Discord.API.AuditLog; @@ -51,6 +51,7 @@ private static readonly Dictionary + /// Represents information for a stage. + /// + public class StageInfo + { + /// + /// Gets the topic of the stage channel. + /// + public string Topic { get; } + + /// + /// Gets the privacy level of the stage channel. + /// + public StagePrivacyLevel? PrivacyLevel { get; } + + /// + /// Gets the user who started the stage channel. + /// + public IUser User { get; } + + internal StageInfo(IUser user, StagePrivacyLevel? level, string topic) + { + Topic = topic; + PrivacyLevel = level; + User = user; + } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/StageInstanceCreateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/StageInstanceCreateAuditLogData.cs new file mode 100644 index 000000000..eac99e87b --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/StageInstanceCreateAuditLogData.cs @@ -0,0 +1,50 @@ +using System.Linq; +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + /// + /// Contains a piece of audit log data related to a stage going live. + /// + public class StageInstanceCreateAuditLogData : IAuditLogData + { + /// + /// Gets the topic of the stage channel. + /// + public string Topic { get; } + + /// + /// Gets the privacy level of the stage channel. + /// + public StagePrivacyLevel PrivacyLevel { get; } + + /// + /// Gets the user who started the stage channel. + /// + public IUser User { get; } + + /// + /// Gets the Id of the stage channel. + /// + public ulong StageChannelId { get; } + + internal StageInstanceCreateAuditLogData(string topic, StagePrivacyLevel privacyLevel, IUser user, ulong channelId) + { + Topic = topic; + PrivacyLevel = privacyLevel; + User = user; + StageChannelId = channelId; + } + + internal static StageInstanceCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var topic = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "topic").NewValue.ToObject(discord.ApiClient.Serializer); + var privacyLevel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "privacy_level").NewValue.ToObject(discord.ApiClient.Serializer); + var user = log.Users.FirstOrDefault(x => x.Id == entry.UserId); + var channelId = entry.Options.ChannelId; + + return new StageInstanceCreateAuditLogData(topic, privacyLevel, RestUser.Create(discord, user), channelId ?? 0); + } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/StageInstanceDeleteAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/StageInstanceDeleteAuditLogData.cs new file mode 100644 index 000000000..d22c56010 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/StageInstanceDeleteAuditLogData.cs @@ -0,0 +1,50 @@ +using System.Linq; +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + /// + /// Contains a piece of audit log data related to a stage instance deleted. + /// + public class StageInstanceDeleteAuditLogData + { + /// + /// Gets the topic of the stage channel. + /// + public string Topic { get; } + + /// + /// Gets the privacy level of the stage channel. + /// + public StagePrivacyLevel PrivacyLevel { get; } + + /// + /// Gets the user who started the stage channel. + /// + public IUser User { get; } + + /// + /// Gets the Id of the stage channel. + /// + public ulong StageChannelId { get; } + + internal StageInstanceDeleteAuditLogData(string topic, StagePrivacyLevel privacyLevel, IUser user, ulong channelId) + { + Topic = topic; + PrivacyLevel = privacyLevel; + User = user; + StageChannelId = channelId; + } + + internal static StageInstanceDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var topic = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "topic").OldValue.ToObject(discord.ApiClient.Serializer); + var privacyLevel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "privacy_level").OldValue.ToObject(discord.ApiClient.Serializer); + var user = log.Users.FirstOrDefault(x => x.Id == entry.UserId); + var channelId = entry.Options.ChannelId; + + return new StageInstanceDeleteAuditLogData(topic, privacyLevel, RestUser.Create(discord, user), channelId ?? 0); + } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/StageInstanceUpdatedAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/StageInstanceUpdatedAuditLogData.cs new file mode 100644 index 000000000..93a0344b2 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/StageInstanceUpdatedAuditLogData.cs @@ -0,0 +1,51 @@ +using System.Linq; +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; + +namespace Discord.Rest +{ + /// + /// Contains a piece of audit log data related to a stage instance update. + /// + public class StageInstanceUpdatedAuditLogData + { + /// + /// Gets the Id of the stage channel. + /// + public ulong StageChannelId { get; } + + /// + /// Gets the stage information before the changes. + /// + public StageInfo Before { get; } + + /// + /// Gets the stage information after the changes. + /// + public StageInfo After { get; } + + internal StageInstanceUpdatedAuditLogData(ulong channelId, StageInfo before, StageInfo after) + { + StageChannelId = channelId; + Before = before; + After = after; + } + + internal static StageInstanceUpdatedAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) + { + var channelId = entry.Options.ChannelId.Value; + + var topic = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "topic"); + var privacy = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "privacy"); + + var user = RestUser.Create(discord, log.Users.FirstOrDefault(x => x.Id == entry.UserId)); + + var oldTopic = topic?.OldValue.ToObject(); + var newTopic = topic?.NewValue.ToObject(); + var oldPrivacy = privacy?.OldValue.ToObject(); + var newPrivacy = privacy?.NewValue.ToObject(); + + return new StageInstanceUpdatedAuditLogData(channelId, new StageInfo(user, oldPrivacy, oldTopic), new StageInfo(user, newPrivacy, newTopic)); + } + } +} diff --git a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs index 22395ab3a..2956d6443 100644 --- a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs +++ b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs @@ -6,12 +6,13 @@ using System.Linq; using System.Threading.Tasks; using Model = Discord.API.Channel; +using StageInstance = Discord.API.StageInstance; namespace Discord.Rest { internal static class ChannelHelper { - //General + #region General public static async Task DeleteAsync(IChannel channel, BaseDiscordClient client, RequestOptions options) { @@ -76,6 +77,7 @@ public static async Task ModifyAsync(IVoiceChannel channel, BaseDiscordCl { Bitrate = args.Bitrate, Name = args.Name, + RTCRegion = args.RTCRegion, Position = args.Position, CategoryId = args.CategoryId, UserLimit = args.UserLimit.IsSpecified ? (args.UserLimit.Value ?? 0) : Optional.Create(), @@ -92,7 +94,23 @@ public static async Task ModifyAsync(IVoiceChannel channel, BaseDiscordCl return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); } - //Invites + public static async Task ModifyAsync(IStageChannel channel, BaseDiscordClient client, + Action func, RequestOptions options = null) + { + var args = new StageInstanceProperties(); + func(args); + + var apiArgs = new ModifyStageInstanceParams() + { + PrivacyLevel = args.PrivacyLevel, + Topic = args.Topic + }; + + return await client.ApiClient.ModifyStageInstanceAsync(channel.Id, apiArgs, options); + } + #endregion + + #region Invites public static async Task> GetInvitesAsync(IGuildChannel channel, BaseDiscordClient client, RequestOptions options) { @@ -120,7 +138,56 @@ public static async Task CreateInviteAsync(IGuildChannel cha return RestInviteMetadata.Create(client, null, channel, model); } - //Messages + /// + /// may not be equal to zero. + /// -and- + /// and must be greater than zero. + /// -and- + /// must be lesser than 86400. + /// + public static async Task CreateInviteToStreamAsync(IGuildChannel channel, BaseDiscordClient client, + int? maxAge, int? maxUses, bool isTemporary, bool isUnique, IUser user, + RequestOptions options) + { + var args = new API.Rest.CreateChannelInviteParams + { + IsTemporary = isTemporary, + IsUnique = isUnique, + MaxAge = maxAge ?? 0, + MaxUses = maxUses ?? 0, + TargetType = TargetUserType.Stream, + TargetUserId = user.Id + }; + var model = await client.ApiClient.CreateChannelInviteAsync(channel.Id, args, options).ConfigureAwait(false); + return RestInviteMetadata.Create(client, null, channel, model); + } + + /// + /// may not be equal to zero. + /// -and- + /// and must be greater than zero. + /// -and- + /// must be lesser than 86400. + /// + public static async Task CreateInviteToApplicationAsync(IGuildChannel channel, BaseDiscordClient client, + int? maxAge, int? maxUses, bool isTemporary, bool isUnique, ulong applicationId, + RequestOptions options) + { + var args = new API.Rest.CreateChannelInviteParams + { + IsTemporary = isTemporary, + IsUnique = isUnique, + MaxAge = maxAge ?? 0, + MaxUses = maxUses ?? 0, + TargetType = TargetUserType.EmbeddedApplication, + TargetApplicationId = applicationId + }; + var model = await client.ApiClient.CreateChannelInviteAsync(channel.Id, args, options).ConfigureAwait(false); + return RestInviteMetadata.Create(client, null, channel, model); + } + #endregion + + #region Messages public static async Task GetMessageAsync(IMessageChannel channel, BaseDiscordClient client, ulong id, RequestOptions options) { @@ -200,10 +267,15 @@ public static async Task> GetPinnedMessagesAsyn /// Message content is too long, length must be less or equal to . public static async Task SendMessageAsync(IMessageChannel channel, BaseDiscordClient client, - string text, bool isTTS, Embed embed, AllowedMentions allowedMentions, MessageReference messageReference, RequestOptions options) + string text, bool isTTS, Embed embed, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, RequestOptions options, Embed[] embeds) { + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); // check that user flag and user Id list are exclusive, same with role flag and role Id list if (allowedMentions != null && allowedMentions.AllowedTypes.HasValue) @@ -221,7 +293,20 @@ public static async Task SendMessageAsync(IMessageChannel chann } } - var args = new CreateMessageParams(text) { IsTTS = isTTS, Embed = embed?.ToModel(), AllowedMentions = allowedMentions?.ToModel(), MessageReference = messageReference?.ToModel() }; + if (stickers != null) + { + Preconditions.AtMost(stickers.Length, 3, nameof(stickers), "A max of 3 stickers are allowed."); + } + + var args = new CreateMessageParams(text) + { + IsTTS = isTTS, + Embeds = embeds.Any() ? embeds.Select(x => x.ToModel()).ToArray() : Optional.Unspecified, + AllowedMentions = allowedMentions?.ToModel(), + MessageReference = messageReference?.ToModel(), + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified, + Stickers = stickers?.Any() ?? false ? stickers.Select(x => x.Id).ToArray() : Optional.Unspecified + }; var model = await client.ApiClient.CreateMessageAsync(channel.Id, args, options).ConfigureAwait(false); return RestUserMessage.Create(client, channel, client.CurrentUser, model); } @@ -251,19 +336,40 @@ public static async Task SendMessageAsync(IMessageChannel chann /// An I/O error occurred while opening the file. /// Message content is too long, length must be less or equal to . public static async Task SendFileAsync(IMessageChannel channel, BaseDiscordClient client, - string filePath, string text, bool isTTS, Embed embed, AllowedMentions allowedMentions, MessageReference messageReference, RequestOptions options, bool isSpoiler) + string filePath, string text, bool isTTS, Embed embed, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, RequestOptions options, bool isSpoiler, Embed[] embeds) { string filename = Path.GetFileName(filePath); using (var file = File.OpenRead(filePath)) - return await SendFileAsync(channel, client, file, filename, text, isTTS, embed, allowedMentions, messageReference, options, isSpoiler).ConfigureAwait(false); + return await SendFileAsync(channel, client, file, filename, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, isSpoiler, embeds).ConfigureAwait(false); } /// Message content is too long, length must be less or equal to . - public static async Task SendFileAsync(IMessageChannel channel, BaseDiscordClient client, - Stream stream, string filename, string text, bool isTTS, Embed embed, AllowedMentions allowedMentions, MessageReference messageReference, RequestOptions options, bool isSpoiler) + public static Task SendFileAsync(IMessageChannel channel, BaseDiscordClient client, + Stream stream, string filename, string text, bool isTTS, Embed embed, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, RequestOptions options, bool isSpoiler, Embed[] embeds) + { + return SendFileAsync(channel, client, new FileAttachment(stream, filename, isSpoiler: isSpoiler), text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); + } + + /// Message content is too long, length must be less or equal to . + public static Task SendFileAsync(IMessageChannel channel, BaseDiscordClient client, + FileAttachment attachment, string text, bool isTTS, Embed embed, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, RequestOptions options, Embed[] embeds) + => SendFilesAsync(channel, client, new[] { attachment }, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); + + public static async Task SendFilesAsync(IMessageChannel channel, BaseDiscordClient client, + IEnumerable attachments, string text, bool isTTS, Embed embed, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, RequestOptions options, Embed[] embeds) { + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + + foreach(var attachment in attachments) + { + Preconditions.NotNullOrEmpty(attachment.FileName, nameof(attachment.FileName), "File Name must not be empty or null"); + } // check that user flag and user Id list are exclusive, same with role flag and role Id list if (allowedMentions != null && allowedMentions.AllowedTypes.HasValue) @@ -281,7 +387,12 @@ public static async Task SendFileAsync(IMessageChannel channel, } } - var args = new UploadFileParams(stream) { Filename = filename, Content = text, IsTTS = isTTS, Embed = embed?.ToModel() ?? Optional.Unspecified, AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, MessageReference = messageReference?.ToModel() ?? Optional.Unspecified, IsSpoiler = isSpoiler }; + if (stickers != null) + { + Preconditions.AtMost(stickers.Length, 3, nameof(stickers), "A max of 3 stickers are allowed."); + } + + var args = new UploadFileParams(attachments.ToArray()) { Content = text, IsTTS = isTTS, Embeds = embeds.Any() ? embeds.Select(x => x.ToModel()).ToArray() : Optional.Unspecified, AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, MessageReference = messageReference?.ToModel() ?? Optional.Unspecified, MessageComponent = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified, Stickers = stickers?.Any() ?? false ? stickers.Select(x => x.Id).ToArray() : Optional.Unspecified }; var model = await client.ApiClient.UploadFileAsync(channel.Id, args, options).ConfigureAwait(false); return RestUserMessage.Create(client, channel, client.CurrentUser, model); } @@ -323,8 +434,9 @@ public static async Task DeleteMessagesAsync(ITextChannel channel, BaseDiscordCl await client.ApiClient.DeleteMessagesAsync(channel.Id, args, options).ConfigureAwait(false); } } + #endregion - //Permission Overwrites + #region Permission Overwrites public static async Task AddPermissionOverwriteAsync(IGuildChannel channel, BaseDiscordClient client, IUser user, OverwritePermissions perms, RequestOptions options) { @@ -347,8 +459,9 @@ public static async Task RemovePermissionOverwriteAsync(IGuildChannel channel, B { await client.ApiClient.DeleteChannelPermissionAsync(channel.Id, role.Id, options).ConfigureAwait(false); } + #endregion - //Users + #region Users /// Resolving permissions requires the parent guild to be downloaded. public static async Task GetUserAsync(IGuildChannel channel, IGuild guild, BaseDiscordClient client, ulong id, RequestOptions options) @@ -393,8 +506,9 @@ public static IAsyncEnumerable> GetUsersAsync count: limit ); } + #endregion - //Typing + #region Typing public static async Task TriggerTypingAsync(IMessageChannel channel, BaseDiscordClient client, RequestOptions options = null) { @@ -403,8 +517,9 @@ public static async Task TriggerTypingAsync(IMessageChannel channel, BaseDiscord public static IDisposable EnterTypingState(IMessageChannel channel, BaseDiscordClient client, RequestOptions options) => new TypingNotifier(channel, options); + #endregion - //Webhooks + #region Webhooks public static async Task CreateWebhookAsync(ITextChannel channel, BaseDiscordClient client, string name, Stream avatar, RequestOptions options) { var args = new CreateWebhookParams { Name = name }; @@ -427,7 +542,9 @@ public static async Task> GetWebhooksAsync(ITex return models.Select(x => RestWebhook.Create(client, channel, x)) .ToImmutableArray(); } - // Categories + #endregion + + #region Categories public static async Task GetCategoryAsync(INestedChannel channel, BaseDiscordClient client, RequestOptions options) { // if no category id specified, return null @@ -441,7 +558,8 @@ public static async Task GetCategoryAsync(INestedChannel chann public static async Task SyncPermissionsAsync(INestedChannel channel, BaseDiscordClient client, RequestOptions options) { var category = await GetCategoryAsync(channel, client, options).ConfigureAwait(false); - if (category == null) throw new InvalidOperationException("This channel does not have a parent channel."); + if (category == null) + throw new InvalidOperationException("This channel does not have a parent channel."); var apiArgs = new ModifyGuildChannelParams { @@ -456,5 +574,6 @@ public static async Task SyncPermissionsAsync(INestedChannel channel, BaseDiscor }; await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); } + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Channels/IRestMessageChannel.cs b/src/Discord.Net.Rest/Entities/Channels/IRestMessageChannel.cs index 09404d836..159735798 100644 --- a/src/Discord.Net.Rest/Entities/Channels/IRestMessageChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/IRestMessageChannel.cs @@ -25,17 +25,20 @@ public interface IRestMessageChannel : IMessageChannel /// If null, all mentioned roles and users will be notified. /// /// The message references to be included. Used to reply to specific messages. + /// The message components to be included with this message. Used for interactions. + /// A collection of stickers to send with the message. + /// A array of s to send with this response. Max 10. /// /// A task that represents an asynchronous send operation for delivering the message. The task result /// contains the sent message. /// - new Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null); + new Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null); /// /// Sends a file to this message channel with an optional caption. /// /// - /// This method follows the same behavior as described in - /// . Please visit + /// This method follows the same behavior as described in + /// . Please visit /// its documentation for more details on this method. /// /// The file path of the file. @@ -49,16 +52,19 @@ public interface IRestMessageChannel : IMessageChannel /// If null, all mentioned roles and users will be notified. /// /// The message references to be included. Used to reply to specific messages. + /// The message components to be included with this message. Used for interactions. + /// A collection of stickers to send with the message. + /// A array of s to send with this response. Max 10. /// /// A task that represents an asynchronous send operation for delivering the message. The task result /// contains the sent message. /// - new Task SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null); + new Task SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null); /// /// Sends a file to this message channel with an optional caption. /// /// - /// This method follows the same behavior as described in . + /// This method follows the same behavior as described in . /// Please visit its documentation for more details on this method. /// /// The of the file to be sent. @@ -73,11 +79,14 @@ public interface IRestMessageChannel : IMessageChannel /// If null, all mentioned roles and users will be notified. /// /// The message references to be included. Used to reply to specific messages. + /// The message components to be included with this message. Used for interactions. + /// A collection of stickers to send with the message. + /// A array of s to send with this response. Max 10. /// /// A task that represents an asynchronous send operation for delivering the message. The task result /// contains the sent message. /// - new Task SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null); + new Task SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null); /// /// Gets a message from this message channel. diff --git a/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs index 177bde21d..9f944501b 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestCategoryChannel.cs @@ -12,6 +12,7 @@ namespace Discord.Rest [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class RestCategoryChannel : RestGuildChannel, ICategoryChannel { + #region RestCategoryChannel internal RestCategoryChannel(BaseDiscordClient discord, IGuild guild, ulong id) : base(discord, guild, id) { @@ -24,8 +25,9 @@ internal RestCategoryChannel(BaseDiscordClient discord, IGuild guild, ulong id) } private string DebuggerDisplay => $"{Name} ({Id}, Category)"; + #endregion - //IChannel + #region IChannel /// /// This method is not supported with category channels. IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) @@ -34,5 +36,6 @@ IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mo /// This method is not supported with category channels. Task IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) => throw new NotSupportedException(); + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Channels/RestChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestChannel.cs index 6f6a1f0d3..83c6d8bfb 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestChannel.cs @@ -11,6 +11,7 @@ namespace Discord.Rest /// public class RestChannel : RestEntity, IChannel, IUpdateable { + #region RestChannel /// public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); @@ -21,40 +22,55 @@ internal RestChannel(BaseDiscordClient discord, ulong id) /// Unexpected channel type. internal static RestChannel Create(BaseDiscordClient discord, Model model) { - switch (model.Type) + return model.Type switch { - case ChannelType.News: - case ChannelType.Text: - case ChannelType.Voice: - return RestGuildChannel.Create(discord, new RestGuild(discord, model.GuildId.Value), model); - case ChannelType.DM: - case ChannelType.Group: - return CreatePrivate(discord, model) as RestChannel; - case ChannelType.Category: - return RestCategoryChannel.Create(discord, new RestGuild(discord, model.GuildId.Value), model); - default: - return new RestChannel(discord, model.Id); - } + ChannelType.News or + ChannelType.Text or + ChannelType.Voice or + ChannelType.Stage or + ChannelType.NewsThread or + ChannelType.PrivateThread or + ChannelType.PublicThread + => RestGuildChannel.Create(discord, new RestGuild(discord, model.GuildId.Value), model), + ChannelType.DM or ChannelType.Group => CreatePrivate(discord, model) as RestChannel, + ChannelType.Category => RestCategoryChannel.Create(discord, new RestGuild(discord, model.GuildId.Value), model), + _ => new RestChannel(discord, model.Id), + }; + } + internal static RestChannel Create(BaseDiscordClient discord, Model model, IGuild guild) + { + return model.Type switch + { + ChannelType.News or + ChannelType.Text or + ChannelType.Voice or + ChannelType.Stage or + ChannelType.NewsThread or + ChannelType.PrivateThread or + ChannelType.PublicThread + => RestGuildChannel.Create(discord, guild, model), + ChannelType.DM or ChannelType.Group => CreatePrivate(discord, model) as RestChannel, + ChannelType.Category => RestCategoryChannel.Create(discord, guild, model), + _ => new RestChannel(discord, model.Id), + }; } /// Unexpected channel type. internal static IRestPrivateChannel CreatePrivate(BaseDiscordClient discord, Model model) { - switch (model.Type) + return model.Type switch { - case ChannelType.DM: - return RestDMChannel.Create(discord, model); - case ChannelType.Group: - return RestGroupChannel.Create(discord, model); - default: - throw new InvalidOperationException($"Unexpected channel type: {model.Type}"); - } + ChannelType.DM => RestDMChannel.Create(discord, model), + ChannelType.Group => RestGroupChannel.Create(discord, model), + _ => throw new InvalidOperationException($"Unexpected channel type: {model.Type}"), + }; } internal virtual void Update(Model model) { } /// public virtual Task UpdateAsync(RequestOptions options = null) => Task.Delay(0); + #endregion - //IChannel + #region IChannel /// string IChannel.Name => null; @@ -64,5 +80,6 @@ Task IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions optio /// IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => AsyncEnumerable.Empty>(); //Overridden + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Channels/RestDMChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestDMChannel.cs index 6ccfd204c..1b91c6e62 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestDMChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestDMChannel.cs @@ -15,6 +15,7 @@ namespace Discord.Rest [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class RestDMChannel : RestChannel, IDMChannel, IRestPrivateChannel, IRestMessageChannel { + #region RestDMChannel /// /// Gets the current logged-in user. /// @@ -93,8 +94,8 @@ public Task> GetPinnedMessagesAsync(RequestOpti /// /// Message content is too long, length must be less or equal to . - public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, allowedMentions, messageReference, options); + public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); /// /// @@ -121,12 +122,22 @@ public Task SendMessageAsync(string text = null, bool isTTS = f /// is in an invalid format. /// An I/O error occurred while opening the file. /// Message content is too long, length must be less or equal to . - public Task SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, allowedMentions, messageReference, options, isSpoiler); + public Task SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, isSpoiler, embeds); /// /// Message content is too long, length must be less or equal to . - public Task SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, allowedMentions, messageReference, options, isSpoiler); + public Task SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, isSpoiler, embeds); + + /// + /// Message content is too long, length must be less or equal to . + public Task SendFileAsync(FileAttachment attachment, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, attachment, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); + + /// + /// Message content is too long, length must be less or equal to . + public Task SendFilesAsync(IEnumerable attachments, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFilesAsync(this, Discord, attachments, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); /// public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null) @@ -154,20 +165,24 @@ public IDisposable EnterTypingState(RequestOptions options = null) /// public override string ToString() => $"@{Recipient}"; private string DebuggerDisplay => $"@{Recipient} ({Id}, DM)"; + #endregion - //IDMChannel + #region IDMChannel /// IUser IDMChannel.Recipient => Recipient; + #endregion - //IRestPrivateChannel + #region IRestPrivateChannel /// IReadOnlyCollection IRestPrivateChannel.Recipients => ImmutableArray.Create(Recipient); + #endregion - //IPrivateChannel + #region IPrivateChannel /// IReadOnlyCollection IPrivateChannel.Recipients => ImmutableArray.Create(Recipient); + #endregion - //IMessageChannel + #region IMessageChannel /// async Task IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) { @@ -204,16 +219,23 @@ IAsyncEnumerable> IMessageChannel.GetMessagesAsync async Task> IMessageChannel.GetPinnedMessagesAsync(RequestOptions options) => await GetPinnedMessagesAsync(options).ConfigureAwait(false); /// - async Task IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendFileAsync(filePath, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(filePath, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + /// + async Task IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(stream, filename, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + /// + async Task IMessageChannel.SendFileAsync(FileAttachment attachment, string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(attachment, text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); /// - async Task IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendFileAsync(stream, filename, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendFilesAsync(IEnumerable attachments, string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFilesAsync(attachments, text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); /// - async Task IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + #endregion - //IChannel + #region IChannel /// string IChannel.Name => $"@{Recipient}"; @@ -223,5 +245,6 @@ Task IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions optio /// IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => ImmutableArray.Create>(Users).ToAsyncEnumerable(); + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs index 2b0ab8b42..83ff3f558 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs @@ -16,6 +16,7 @@ namespace Discord.Rest [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class RestGroupChannel : RestChannel, IGroupChannel, IRestPrivateChannel, IRestMessageChannel, IRestAudioChannel { + #region RestGroupChannel private string _iconId; private ImmutableDictionary _users; @@ -99,8 +100,8 @@ public async Task ModifyMessageAsync(ulong messageId, Action /// Message content is too long, length must be less or equal to . - public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, allowedMentions, messageReference, options); + public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); /// /// @@ -127,13 +128,20 @@ public Task SendMessageAsync(string text = null, bool isTTS = f /// is in an invalid format. /// An I/O error occurred while opening the file. /// Message content is too long, length must be less or equal to . - public Task SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, allowedMentions, messageReference, options, isSpoiler); + public Task SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, isSpoiler, embeds); /// /// Message content is too long, length must be less or equal to . - public Task SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, allowedMentions, messageReference, options, isSpoiler); - + public Task SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, isSpoiler, embeds); + /// + /// Message content is too long, length must be less or equal to . + public Task SendFileAsync(FileAttachment attachment, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, attachment, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); + /// + /// Message content is too long, length must be less or equal to . + public Task SendFilesAsync(IEnumerable attachments, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFilesAsync(this, Discord, attachments, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); /// public Task TriggerTypingAsync(RequestOptions options = null) => ChannelHelper.TriggerTypingAsync(this, Discord, options); @@ -143,14 +151,17 @@ public IDisposable EnterTypingState(RequestOptions options = null) public override string ToString() => Name; private string DebuggerDisplay => $"{Name} ({Id}, Group)"; + #endregion - //ISocketPrivateChannel + #region ISocketPrivateChannel IReadOnlyCollection IRestPrivateChannel.Recipients => Recipients; + #endregion - //IPrivateChannel + #region IPrivateChannel IReadOnlyCollection IPrivateChannel.Recipients => Recipients; + #endregion - //IMessageChannel + #region IMessageChannel async Task IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) @@ -182,25 +193,31 @@ IAsyncEnumerable> IMessageChannel.GetMessagesAsync async Task> IMessageChannel.GetPinnedMessagesAsync(RequestOptions options) => await GetPinnedMessagesAsync(options).ConfigureAwait(false); - async Task IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendFileAsync(filePath, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference).ConfigureAwait(false); - - async Task IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendFileAsync(stream, filename, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(filePath, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); - async Task IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(stream, filename, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + async Task IMessageChannel.SendFileAsync(FileAttachment attachment, string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(attachment, text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + async Task IMessageChannel.SendFilesAsync(IEnumerable attachments, string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFilesAsync(attachments, text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + async Task IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + #endregion - //IAudioChannel + #region IAudioChannel /// /// Connecting to a group channel is not supported. Task IAudioChannel.ConnectAsync(bool selfDeaf, bool selfMute, bool external) { throw new NotSupportedException(); } Task IAudioChannel.DisconnectAsync() { throw new NotSupportedException(); } + #endregion - //IChannel + #region IChannel Task IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) => Task.FromResult(GetUser(id)); IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => ImmutableArray.Create>(Users).ToAsyncEnumerable(); + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs index fdfee39ea..bc9d4110a 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestGuildChannel.cs @@ -12,6 +12,7 @@ namespace Discord.Rest /// public class RestGuildChannel : RestChannel, IGuildChannel { + #region RestGuildChannel private ImmutableArray _overwrites; /// @@ -32,30 +33,34 @@ internal RestGuildChannel(BaseDiscordClient discord, IGuild guild, ulong id) } internal static RestGuildChannel Create(BaseDiscordClient discord, IGuild guild, Model model) { - switch (model.Type) + return model.Type switch { - case ChannelType.News: - return RestNewsChannel.Create(discord, guild, model); - case ChannelType.Text: - return RestTextChannel.Create(discord, guild, model); - case ChannelType.Voice: - return RestVoiceChannel.Create(discord, guild, model); - case ChannelType.Category: - return RestCategoryChannel.Create(discord, guild, model); - default: - return new RestGuildChannel(discord, guild, model.Id); - } + ChannelType.News => RestNewsChannel.Create(discord, guild, model), + ChannelType.Text => RestTextChannel.Create(discord, guild, model), + ChannelType.Voice => RestVoiceChannel.Create(discord, guild, model), + ChannelType.Stage => RestStageChannel.Create(discord, guild, model), + ChannelType.Category => RestCategoryChannel.Create(discord, guild, model), + ChannelType.PublicThread or ChannelType.PrivateThread or ChannelType.NewsThread => RestThreadChannel.Create(discord, guild, model), + _ => new RestGuildChannel(discord, guild, model.Id), + }; } internal override void Update(Model model) { Name = model.Name.Value; - Position = model.Position.Value; - var overwrites = model.PermissionOverwrites.Value; - var newOverwrites = ImmutableArray.CreateBuilder(overwrites.Length); - for (int i = 0; i < overwrites.Length; i++) - newOverwrites.Add(overwrites[i].ToEntity()); - _overwrites = newOverwrites.ToImmutable(); + if (model.Position.IsSpecified) + { + Position = model.Position.Value; + } + + if (model.PermissionOverwrites.IsSpecified) + { + var overwrites = model.PermissionOverwrites.Value; + var newOverwrites = ImmutableArray.CreateBuilder(overwrites.Length); + for (int i = 0; i < overwrites.Length; i++) + newOverwrites.Add(overwrites[i].ToEntity()); + _overwrites = newOverwrites.ToImmutable(); + } } /// @@ -187,8 +192,9 @@ public virtual async Task RemovePermissionOverwriteAsync(IRole role, RequestOpti /// A string that is the name of this channel. /// public override string ToString() => Name; + #endregion - //IGuildChannel + #region IGuildChannel /// IGuild IGuildChannel.Guild { @@ -225,13 +231,15 @@ IAsyncEnumerable> IGuildChannel.GetUsersAsync(Ca /// Task IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) => Task.FromResult(null); //Overridden in Text/Voice + #endregion - //IChannel + #region IChannel /// IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => AsyncEnumerable.Empty>(); //Overridden in Text/Voice /// Task IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) => Task.FromResult(null); //Overridden in Text/Voice + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Channels/RestStageChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestStageChannel.cs new file mode 100644 index 000000000..c01df96fd --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Channels/RestStageChannel.cs @@ -0,0 +1,150 @@ +using Discord.API; +using Discord.API.Rest; +using System; +using System.Threading.Tasks; +using Model = Discord.API.Channel; + +namespace Discord.Rest +{ + /// + /// Represents a REST-based stage channel in a guild. + /// + public class RestStageChannel : RestVoiceChannel, IStageChannel + { + /// + public string Topic { get; private set; } + + /// + public StagePrivacyLevel? PrivacyLevel { get; private set; } + + /// + public bool? IsDiscoverableDisabled { get; private set; } + + /// + public bool IsLive { get; private set; } + internal RestStageChannel(BaseDiscordClient discord, IGuild guild, ulong id) + : base(discord, guild, id) { } + + internal new static RestStageChannel Create(BaseDiscordClient discord, IGuild guild, Model model) + { + var entity = new RestStageChannel(discord, guild, model.Id); + entity.Update(model); + return entity; + } + + internal void Update(StageInstance model, bool isLive = false) + { + IsLive = isLive; + if(isLive) + { + Topic = model.Topic; + PrivacyLevel = model.PrivacyLevel; + IsDiscoverableDisabled = model.DiscoverableDisabled; + } + else + { + Topic = null; + PrivacyLevel = null; + IsDiscoverableDisabled = null; + } + } + + /// + public async Task ModifyInstanceAsync(Action func, RequestOptions options = null) + { + var model = await ChannelHelper.ModifyAsync(this, Discord, func, options); + + Update(model, true); + } + + /// + public async Task StartStageAsync(string topic, StagePrivacyLevel privacyLevel = StagePrivacyLevel.GuildOnly, RequestOptions options = null) + { + var args = new CreateStageInstanceParams + { + ChannelId = Id, + PrivacyLevel = privacyLevel, + Topic = topic + }; + + var model = await Discord.ApiClient.CreateStageInstanceAsync(args, options); + + Update(model, true); + } + + /// + public async Task StopStageAsync(RequestOptions options = null) + { + await Discord.ApiClient.DeleteStageInstanceAsync(Id, options); + + Update(null); + } + + /// + public override async Task UpdateAsync(RequestOptions options = null) + { + await base.UpdateAsync(options); + + var model = await Discord.ApiClient.GetStageInstanceAsync(Id, options); + + Update(model, model != null); + } + + /// + public Task RequestToSpeakAsync(RequestOptions options = null) + { + var args = new ModifyVoiceStateParams + { + ChannelId = Id, + RequestToSpeakTimestamp = DateTimeOffset.UtcNow + }; + return Discord.ApiClient.ModifyMyVoiceState(Guild.Id, args, options); + } + + /// + public Task BecomeSpeakerAsync(RequestOptions options = null) + { + var args = new ModifyVoiceStateParams + { + ChannelId = Id, + Suppressed = false + }; + return Discord.ApiClient.ModifyMyVoiceState(Guild.Id, args, options); + } + + /// + public Task StopSpeakingAsync(RequestOptions options = null) + { + var args = new ModifyVoiceStateParams + { + ChannelId = Id, + Suppressed = true + }; + return Discord.ApiClient.ModifyMyVoiceState(Guild.Id, args, options); + } + + /// + public Task MoveToSpeakerAsync(IGuildUser user, RequestOptions options = null) + { + var args = new ModifyVoiceStateParams + { + ChannelId = Id, + Suppressed = false + }; + + return Discord.ApiClient.ModifyUserVoiceState(Guild.Id, user.Id, args); + } + + /// + public Task RemoveFromSpeakerAsync(IGuildUser user, RequestOptions options = null) + { + var args = new ModifyVoiceStateParams + { + ChannelId = Id, + Suppressed = true + }; + + return Discord.ApiClient.ModifyUserVoiceState(Guild.Id, user.Id, args); + } + } +} diff --git a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs index c6d0b0509..f14bc2ecf 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs @@ -14,10 +14,11 @@ namespace Discord.Rest [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class RestTextChannel : RestGuildChannel, IRestMessageChannel, ITextChannel { + #region RestTextChannel /// public string Topic { get; private set; } /// - public virtual int SlowModeInterval { get; private set; } + public virtual int SlowModeInterval { get; private set; } /// public ulong? CategoryId { get; private set; } @@ -41,14 +42,14 @@ internal override void Update(Model model) { base.Update(model); CategoryId = model.CategoryId; - Topic = model.Topic.Value; + Topic = model.Topic.GetValueOrDefault(); if (model.SlowMode.IsSpecified) SlowModeInterval = model.SlowMode.Value; IsNsfw = model.Nsfw.GetValueOrDefault(); } /// - public async Task ModifyAsync(Action func, RequestOptions options = null) + public virtual async Task ModifyAsync(Action func, RequestOptions options = null) { var model = await ChannelHelper.ModifyAsync(this, Discord, func, options).ConfigureAwait(false); Update(model); @@ -78,7 +79,7 @@ public Task GetUserAsync(ulong id, RequestOptions options = null) /// /// /// A paged collection containing a collection of guild users that can access this channel. Flattening the - /// paginated response into a collection of users with + /// paginated response into a collection of users with /// is required if you wish to access the users. /// public IAsyncEnumerable> GetUsersAsync(RequestOptions options = null) @@ -102,8 +103,8 @@ public Task> GetPinnedMessagesAsync(RequestOpti /// /// Message content is too long, length must be less or equal to . - public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, allowedMentions, messageReference, options); + public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); /// /// @@ -130,13 +131,23 @@ public Task SendMessageAsync(string text = null, bool isTTS = f /// is in an invalid format. /// An I/O error occurred while opening the file. /// Message content is too long, length must be less or equal to . - public Task SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, allowedMentions, messageReference, options, isSpoiler); + public Task SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, isSpoiler, embeds); /// /// Message content is too long, length must be less or equal to . - public Task SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, allowedMentions, messageReference, options, isSpoiler); + public Task SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, isSpoiler, embeds); + + /// + /// Message content is too long, length must be less or equal to . + public Task SendFileAsync(FileAttachment attachment, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, attachment, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); + + /// + /// Message content is too long, length must be less or equal to . + public Task SendFilesAsync(IEnumerable attachments, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFilesAsync(this, Discord, attachments, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); /// public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null) @@ -173,7 +184,7 @@ public IDisposable EnterTypingState(RequestOptions options = null) /// A task that represents the asynchronous creation operation. The task result contains the newly created /// webhook. /// - public Task CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null) + public virtual Task CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null) => ChannelHelper.CreateWebhookAsync(this, Discord, name, avatar, options); /// /// Gets a webhook available in this text channel. @@ -184,7 +195,7 @@ public Task CreateWebhookAsync(string name, Stream avatar = null, R /// A task that represents the asynchronous get operation. The task result contains a webhook associated /// with the identifier; null if the webhook is not found. /// - public Task GetWebhookAsync(ulong id, RequestOptions options = null) + public virtual Task GetWebhookAsync(ulong id, RequestOptions options = null) => ChannelHelper.GetWebhookAsync(this, Discord, id, options); /// /// Gets the webhooks available in this text channel. @@ -194,7 +205,7 @@ public Task GetWebhookAsync(ulong id, RequestOptions options = null /// A task that represents the asynchronous get operation. The task result contains a read-only collection /// of webhooks that is available in this channel. /// - public Task> GetWebhooksAsync(RequestOptions options = null) + public virtual Task> GetWebhooksAsync(RequestOptions options = null) => ChannelHelper.GetWebhooksAsync(this, Discord, options); /// @@ -205,23 +216,66 @@ public Task> GetWebhooksAsync(RequestOptions op /// A task that represents the asynchronous get operation. The task result contains the category channel /// representing the parent of this channel; null if none is set. /// - public Task GetCategoryAsync(RequestOptions options = null) + public virtual Task GetCategoryAsync(RequestOptions options = null) => ChannelHelper.GetCategoryAsync(this, Discord, options); /// public Task SyncPermissionsAsync(RequestOptions options = null) => ChannelHelper.SyncPermissionsAsync(this, Discord, options); + #endregion - //Invites + #region Invites /// - public async Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + public virtual async Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); + public virtual Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); + public virtual Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); /// - public async Task> GetInvitesAsync(RequestOptions options = null) + public virtual async Task> GetInvitesAsync(RequestOptions options = null) => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); private string DebuggerDisplay => $"{Name} ({Id}, Text)"; - //ITextChannel + /// + /// Creates a thread within this . + /// + /// + /// When is the thread type will be based off of the + /// channel its created in. When called on a , it creates a . + /// When called on a , it creates a . The id of the created + /// thread will be the same as the id of the message, and as such a message can only have a + /// single thread created from it. + /// + /// The name of the thread. + /// + /// The type of the thread. + /// + /// Note: This parameter is not used if the parameter is not specified. + /// + /// + /// + /// The duration on which this thread archives after. + /// + /// Note: Options and + /// are only available for guilds that are boosted. You can check in the to see if the + /// guild has the THREE_DAY_THREAD_ARCHIVE and SEVEN_DAY_THREAD_ARCHIVE. + /// + /// + /// The message which to start the thread from. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous create operation. The task result contains a + /// + public async Task CreateThreadAsync(string name, ThreadType type = ThreadType.PublicThread, + ThreadArchiveDuration autoArchiveDuration = ThreadArchiveDuration.OneDay, IMessage message = null, bool? invitable = null, int? slowmode = null, RequestOptions options = null) + { + var model = await ThreadHelper.CreateThreadAsync(Discord, this, name, type, autoArchiveDuration, message, invitable, slowmode, options); + return RestThreadChannel.Create(Discord, Guild, model); + } + #endregion + + #region ITextChannel /// async Task ITextChannel.CreateWebhookAsync(string name, Stream avatar, RequestOptions options) => await CreateWebhookAsync(name, avatar, options).ConfigureAwait(false); @@ -232,7 +286,11 @@ async Task ITextChannel.GetWebhookAsync(ulong id, RequestOptions optio async Task> ITextChannel.GetWebhooksAsync(RequestOptions options) => await GetWebhooksAsync(options).ConfigureAwait(false); - //IMessageChannel + async Task ITextChannel.CreateThreadAsync(string name, ThreadType type, ThreadArchiveDuration autoArchiveDuration, IMessage message, bool? invitable, int? slowmode, RequestOptions options) + => await CreateThreadAsync(name, type, autoArchiveDuration, message, invitable, slowmode, options); + #endregion + + #region IMessageChannel /// async Task IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) { @@ -271,17 +329,27 @@ async Task> IMessageChannel.GetPinnedMessagesAsync => await GetPinnedMessagesAsync(options).ConfigureAwait(false); /// - async Task IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendFileAsync(filePath, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(filePath, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); /// - async Task IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendFileAsync(stream, filename, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(stream, filename, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + + /// + async Task IMessageChannel.SendFileAsync(FileAttachment attachment, string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(attachment, text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + + /// + async Task IMessageChannel.SendFilesAsync(IEnumerable attachments, string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFilesAsync(attachments, text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + /// - async Task IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + #endregion - //IGuildChannel + #region IGuildChannel /// async Task IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) { @@ -298,8 +366,9 @@ IAsyncEnumerable> IGuildChannel.GetUsersAsync(Ca else return AsyncEnumerable.Empty>(); } + #endregion - //IChannel + #region IChannel /// async Task IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) { @@ -316,8 +385,9 @@ IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mo else return AsyncEnumerable.Empty>(); } + #endregion - // INestedChannel + #region INestedChannel /// async Task INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options) { @@ -325,5 +395,6 @@ async Task INestedChannel.GetCategoryAsync(CacheMode mode, Req return (await Guild.GetChannelAsync(CategoryId.Value, mode, options).ConfigureAwait(false)) as ICategoryChannel; return null; } + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Channels/RestThreadChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestThreadChannel.cs new file mode 100644 index 000000000..63071b9a5 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Channels/RestThreadChannel.cs @@ -0,0 +1,223 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Threading.Tasks; +using Model = Discord.API.Channel; + +namespace Discord.Rest +{ + /// + /// Represents a thread channel received over REST. + /// + public class RestThreadChannel : RestTextChannel, IThreadChannel + { + public ThreadType Type { get; private set; } + /// + public bool HasJoined { get; private set; } + + /// + public bool IsArchived { get; private set; } + + /// + public ThreadArchiveDuration AutoArchiveDuration { get; private set; } + + /// + public DateTimeOffset ArchiveTimestamp { get; private set; } + + /// + public bool IsLocked { get; private set; } + + /// + public int MemberCount { get; private set; } + + /// + public int MessageCount { get; private set; } + + /// + /// Gets the parent text channel id. + /// + public ulong ParentChannelId { get; private set; } + + internal RestThreadChannel(BaseDiscordClient discord, IGuild guild, ulong id) + : base(discord, guild, id) { } + + internal new static RestThreadChannel Create(BaseDiscordClient discord, IGuild guild, Model model) + { + var entity = new RestThreadChannel(discord, guild, model.Id); + entity.Update(model); + return entity; + } + + internal override void Update(Model model) + { + base.Update(model); + + HasJoined = model.ThreadMember.IsSpecified; + + if (model.ThreadMetadata.IsSpecified) + { + IsArchived = model.ThreadMetadata.Value.Archived; + AutoArchiveDuration = model.ThreadMetadata.Value.AutoArchiveDuration; + ArchiveTimestamp = model.ThreadMetadata.Value.ArchiveTimestamp; + IsLocked = model.ThreadMetadata.Value.Locked.GetValueOrDefault(false); + } + + MemberCount = model.MemberCount.GetValueOrDefault(0); + MessageCount = model.MessageCount.GetValueOrDefault(0); + Type = (ThreadType)model.Type; + ParentChannelId = model.CategoryId.Value; + } + + /// + /// Gets a user within this thread. + /// + /// The id of the user to fetch. + /// The options to be used when sending the request. + /// + /// A task representing the asynchronous get operation. The task returns a + /// if found, otherwise . + /// + public new Task GetUserAsync(ulong userId, RequestOptions options = null) + => ThreadHelper.GetUserAsync(userId, this, Discord, options); + + /// + /// Gets a collection of users within this thread. + /// + /// The options to be used when sending the request. + /// + /// A task representing the asynchronous get operation. The task returns a + /// of 's. + /// + public new async Task> GetUsersAsync(RequestOptions options = null) + => (await ThreadHelper.GetUsersAsync(this, Discord, options).ConfigureAwait(false)).ToImmutableArray(); + + /// + public override async Task ModifyAsync(Action func, RequestOptions options = null) + { + var model = await ThreadHelper.ModifyAsync(this, Discord, func, options); + Update(model); + } + + /// + /// + /// This method is not supported in threads. + /// + public override Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task AddPermissionOverwriteAsync(IUser user, OverwritePermissions permissions, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task GetCategoryAsync(RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task> GetInvitesAsync(RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override OverwritePermissions? GetPermissionOverwrite(IRole role) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override OverwritePermissions? GetPermissionOverwrite(IUser user) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task GetWebhookAsync(ulong id, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task> GetWebhooksAsync(RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task RemovePermissionOverwriteAsync(IRole role, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task RemovePermissionOverwriteAsync(IUser user, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override IReadOnlyCollection PermissionOverwrites + => throw new NotSupportedException("This method is not supported in threads."); + + /// + public Task JoinAsync(RequestOptions options = null) + => Discord.ApiClient.JoinThreadAsync(Id, options); + + /// + public Task LeaveAsync(RequestOptions options = null) + => Discord.ApiClient.LeaveThreadAsync(Id, options); + + /// + public Task AddUserAsync(IGuildUser user, RequestOptions options = null) + => Discord.ApiClient.AddThreadMemberAsync(Id, user.Id, options); + + /// + public Task RemoveUserAsync(IGuildUser user, RequestOptions options = null) + => Discord.ApiClient.RemoveThreadMemberAsync(Id, user.Id, options); + } +} diff --git a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs index e958f2c03..48fc11dcb 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs @@ -14,6 +14,7 @@ namespace Discord.Rest [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class RestVoiceChannel : RestGuildChannel, IVoiceChannel, IRestAudioChannel { + #region RestVoiceChannel /// public int Bitrate { get; private set; } /// @@ -39,8 +40,12 @@ internal override void Update(Model model) { base.Update(model); CategoryId = model.CategoryId; - Bitrate = model.Bitrate.Value; - UserLimit = model.UserLimit.Value != 0 ? model.UserLimit.Value : (int?)null; + + if(model.Bitrate.IsSpecified) + Bitrate = model.Bitrate.Value; + + if(model.UserLimit.IsSpecified) + UserLimit = model.UserLimit.Value != 0 ? model.UserLimit.Value : (int?)null; } /// @@ -63,32 +68,42 @@ public Task GetCategoryAsync(RequestOptions options = null) /// public Task SyncPermissionsAsync(RequestOptions options = null) => ChannelHelper.SyncPermissionsAsync(this, Discord, options); + #endregion - //Invites + #region Invites /// public async Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); /// + public async Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options).ConfigureAwait(false); + /// + public async Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToStreamAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, user, options).ConfigureAwait(false); + /// public async Task> GetInvitesAsync(RequestOptions options = null) => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); private string DebuggerDisplay => $"{Name} ({Id}, Voice)"; + #endregion - //IAudioChannel + #region IAudioChannel /// /// Connecting to a REST-based channel is not supported. Task IAudioChannel.ConnectAsync(bool selfDeaf, bool selfMute, bool external) { throw new NotSupportedException(); } Task IAudioChannel.DisconnectAsync() { throw new NotSupportedException(); } + #endregion - //IGuildChannel + #region IGuildChannel /// Task IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) => Task.FromResult(null); /// IAsyncEnumerable> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => AsyncEnumerable.Empty>(); + #endregion - // INestedChannel + #region INestedChannel /// async Task INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options) { @@ -96,5 +111,6 @@ async Task INestedChannel.GetCategoryAsync(CacheMode mode, Req return (await Guild.GetChannelAsync(CategoryId.Value, mode, options).ConfigureAwait(false)) as ICategoryChannel; return null; } + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Channels/ThreadHelper.cs b/src/Discord.Net.Rest/Entities/Channels/ThreadHelper.cs new file mode 100644 index 000000000..917410f98 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Channels/ThreadHelper.cs @@ -0,0 +1,74 @@ +using Discord.API.Rest; +using System; +using System.Linq; +using System.Threading.Tasks; +using Model = Discord.API.Channel; + +namespace Discord.Rest +{ + internal static class ThreadHelper + { + public static async Task CreateThreadAsync(BaseDiscordClient client, ITextChannel channel, string name, ThreadType type = ThreadType.PublicThread, + ThreadArchiveDuration autoArchiveDuration = ThreadArchiveDuration.OneDay, IMessage message = null, bool? invitable = null, int? slowmode = null, RequestOptions options = null) + { + var features = channel.Guild.Features; + if (autoArchiveDuration == ThreadArchiveDuration.OneWeek && !features.HasFeature(GuildFeature.SevenDayThreadArchive)) + throw new ArgumentException($"The guild {channel.Guild.Name} does not have the SEVEN_DAY_THREAD_ARCHIVE feature!", nameof(autoArchiveDuration)); + + if (autoArchiveDuration == ThreadArchiveDuration.ThreeDays && !features.HasFeature(GuildFeature.ThreeDayThreadArchive)) + throw new ArgumentException($"The guild {channel.Guild.Name} does not have the THREE_DAY_THREAD_ARCHIVE feature!", nameof(autoArchiveDuration)); + + if (type == ThreadType.PrivateThread && !features.HasFeature(GuildFeature.PrivateThreads)) + throw new ArgumentException($"The guild {channel.Guild.Name} does not have the PRIVATE_THREADS feature!", nameof(type)); + + var args = new StartThreadParams + { + Name = name, + Duration = autoArchiveDuration, + Type = type, + Invitable = invitable.HasValue ? invitable.Value : Optional.Unspecified, + Ratelimit = slowmode.HasValue ? slowmode.Value : Optional.Unspecified, + }; + + Model model; + + if (message != null) + model = await client.ApiClient.StartThreadAsync(channel.Id, message.Id, args, options).ConfigureAwait(false); + else + model = await client.ApiClient.StartThreadAsync(channel.Id, args, options).ConfigureAwait(false); + + return model; + } + + public static async Task ModifyAsync(IThreadChannel channel, BaseDiscordClient client, + Action func, + RequestOptions options) + { + var args = new TextChannelProperties(); + func(args); + var apiArgs = new ModifyThreadParams + { + Name = args.Name, + Archived = args.Archived, + AutoArchiveDuration = args.AutoArchiveDuration, + Locked = args.Locked, + Slowmode = args.SlowModeInterval + }; + return await client.ApiClient.ModifyThreadAsync(channel.Id, apiArgs, options).ConfigureAwait(false); + } + + public static async Task GetUsersAsync(IThreadChannel channel, BaseDiscordClient client, RequestOptions options = null) + { + var users = await client.ApiClient.ListThreadMembersAsync(channel.Id, options); + + return users.Select(x => RestThreadUser.Create(client, channel.Guild, x, channel)).ToArray(); + } + + public static async Task GetUserAsync(ulong userId, IThreadChannel channel, BaseDiscordClient client, RequestOptions options = null) + { + var model = await client.ApiClient.GetThreadMemberAsync(channel.Id, userId, options).ConfigureAwait(false); + + return RestThreadUser.Create(client, channel.Guild, model, channel); + } + } +} diff --git a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs index 58a4ea2c8..2cdbbb7b5 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs @@ -8,12 +8,13 @@ using Model = Discord.API.Guild; using RoleModel = Discord.API.Role; using ImageModel = Discord.API.Image; +using System.IO; namespace Discord.Rest { internal static class GuildHelper { - //General + #region General /// is null. public static async Task ModifyAsync(IGuild guild, BaseDiscordClient client, Action func, RequestOptions options) @@ -35,7 +36,8 @@ public static async Task ModifyAsync(IGuild guild, BaseDiscordClient clie Banner = args.Banner.IsSpecified ? args.Banner.Value?.ToModel() : Optional.Create(), VerificationLevel = args.VerificationLevel, ExplicitContentFilter = args.ExplicitContentFilter, - SystemChannelFlags = args.SystemChannelFlags + SystemChannelFlags = args.SystemChannelFlags, + IsBoostProgressBarEnabled = args.IsBoostProgressBarEnabled }; if (args.AfkChannel.IsSpecified) @@ -122,8 +124,9 @@ public static async Task DeleteAsync(IGuild guild, BaseDiscordClient client, { await client.ApiClient.DeleteGuildAsync(guild.Id, options).ConfigureAwait(false); } + #endregion - //Bans + #region Bans public static async Task> GetBansAsync(IGuild guild, BaseDiscordClient client, RequestOptions options) { @@ -147,8 +150,9 @@ public static async Task RemoveBanAsync(IGuild guild, BaseDiscordClient client, { await client.ApiClient.RemoveGuildBanAsync(guild.Id, userId, options).ConfigureAwait(false); } + #endregion - //Channels + #region Channels public static async Task GetChannelAsync(IGuild guild, BaseDiscordClient client, ulong id, RequestOptions options) { @@ -220,6 +224,34 @@ public static async Task CreateVoiceChannelAsync(IGuild guild, var model = await client.ApiClient.CreateGuildChannelAsync(guild.Id, args, options).ConfigureAwait(false); return RestVoiceChannel.Create(client, guild, model); } + public static async Task CreateStageChannelAsync(IGuild guild, BaseDiscordClient client, + string name, RequestOptions options, Action func = null) + { + if (name == null) + throw new ArgumentNullException(paramName: nameof(name)); + + var props = new VoiceChannelProperties(); + func?.Invoke(props); + + var args = new CreateGuildChannelParams(name, ChannelType.Stage) + { + CategoryId = props.CategoryId, + Bitrate = props.Bitrate, + UserLimit = props.UserLimit, + Position = props.Position, + Overwrites = props.PermissionOverwrites.IsSpecified + ? props.PermissionOverwrites.Value.Select(overwrite => new API.Overwrite + { + TargetId = overwrite.TargetId, + TargetType = overwrite.TargetType, + Allow = overwrite.Permissions.AllowValue.ToString(), + Deny = overwrite.Permissions.DenyValue.ToString() + }).ToArray() + : Optional.Create(), + }; + var model = await client.ApiClient.CreateGuildChannelAsync(guild.Id, args, options).ConfigureAwait(false); + return RestStageChannel.Create(client, guild, model); + } /// is null. public static async Task CreateCategoryChannelAsync(IGuild guild, BaseDiscordClient client, string name, RequestOptions options, Action func = null) @@ -246,16 +278,18 @@ public static async Task CreateCategoryChannelAsync(IGuild var model = await client.ApiClient.CreateGuildChannelAsync(guild.Id, args, options).ConfigureAwait(false); return RestCategoryChannel.Create(client, guild, model); } + #endregion - //Voice Regions + #region Voice Regions public static async Task> GetVoiceRegionsAsync(IGuild guild, BaseDiscordClient client, RequestOptions options) { var models = await client.ApiClient.GetGuildVoiceRegionsAsync(guild.Id, options).ConfigureAwait(false); return models.Select(x => RestVoiceRegion.Create(client, x)).ToImmutableArray(); } + #endregion - //Integrations + #region Integrations public static async Task> GetIntegrationsAsync(IGuild guild, BaseDiscordClient client, RequestOptions options) { @@ -269,8 +303,24 @@ public static async Task CreateIntegrationAsync(IGuild gui var model = await client.ApiClient.CreateGuildIntegrationAsync(guild.Id, args, options).ConfigureAwait(false); return RestGuildIntegration.Create(client, guild, model); } + #endregion + + #region Interactions + public static async Task> GetSlashCommandsAsync(IGuild guild, BaseDiscordClient client, + RequestOptions options) + { + var models = await client.ApiClient.GetGuildApplicationCommandsAsync(guild.Id, options); + return models.Select(x => RestGuildCommand.Create(client, x, guild.Id)).ToImmutableArray(); + } + public static async Task GetSlashCommandAsync(IGuild guild, ulong id, BaseDiscordClient client, + RequestOptions options) + { + var model = await client.ApiClient.GetGuildApplicationCommandAsync(guild.Id, id, options); + return RestGuildCommand.Create(client, model, guild.Id); + } + #endregion - //Invites + #region Invites public static async Task> GetInvitesAsync(IGuild guild, BaseDiscordClient client, RequestOptions options) { @@ -286,8 +336,9 @@ public static async Task GetVanityInviteAsync(IGuild guild, inviteModel.Uses = vanityModel.Uses; return RestInviteMetadata.Create(client, guild, null, inviteModel); } + #endregion - //Roles + #region Roles /// is null. public static async Task CreateRoleAsync(IGuild guild, BaseDiscordClient client, string name, GuildPermissions? permissions, Color? color, bool isHoisted, bool isMentionable, RequestOptions options) @@ -307,8 +358,9 @@ public static async Task CreateRoleAsync(IGuild guild, BaseDiscordClie return RestRole.Create(client, guild, model); } + #endregion - //Users + #region Users public static async Task AddGuildUserAsync(IGuild guild, BaseDiscordClient client, ulong userId, string accessToken, Action func, RequestOptions options) { @@ -427,8 +479,9 @@ public static async Task> SearchUsersAsync(IG var models = await client.ApiClient.SearchGuildMembersAsync(guild.Id, apiArgs, options).ConfigureAwait(false); return models.Select(x => RestGuildUser.Create(client, guild, x)).ToImmutableArray(); } + #endregion - // Audit logs + #region Audit logs public static IAsyncEnumerable> GetAuditLogsAsync(IGuild guild, BaseDiscordClient client, ulong? from, int? limit, RequestOptions options, ulong? userId = null, ActionType? actionType = null) { @@ -460,8 +513,9 @@ public static IAsyncEnumerable> GetAuditL count: limit ); } + #endregion - //Webhooks + #region Webhooks public static async Task GetWebhookAsync(IGuild guild, BaseDiscordClient client, ulong id, RequestOptions options) { var model = await client.ApiClient.GetWebhookAsync(id, options: options).ConfigureAwait(false); @@ -474,8 +528,9 @@ public static async Task> GetWebhooksAsync(IGui var models = await client.ApiClient.GetGuildWebhooksAsync(guild.Id, options).ConfigureAwait(false); return models.Select(x => RestWebhook.Create(client, guild, x)).ToImmutableArray(); } + #endregion - //Emotes + #region Emotes public static async Task> GetEmotesAsync(IGuild guild, BaseDiscordClient client, RequestOptions options) { var models = await client.ApiClient.GetGuildEmotesAsync(guild.Id, options).ConfigureAwait(false); @@ -521,5 +576,308 @@ public static async Task ModifyEmoteAsync(IGuild guild, BaseDiscordC } public static Task DeleteEmoteAsync(IGuild guild, BaseDiscordClient client, ulong id, RequestOptions options) => client.ApiClient.DeleteGuildEmoteAsync(guild.Id, id, options); + + public static async Task CreateStickerAsync(BaseDiscordClient client, IGuild guild, string name, string description, IEnumerable tags, + Image image, RequestOptions options = null) + { + Preconditions.NotNull(name, nameof(name)); + Preconditions.NotNull(description, nameof(description)); + + Preconditions.AtLeast(name.Length, 2, nameof(name)); + Preconditions.AtLeast(description.Length, 2, nameof(description)); + + Preconditions.AtMost(name.Length, 30, nameof(name)); + Preconditions.AtMost(description.Length, 100, nameof(name)); + + var apiArgs = new CreateStickerParams() + { + Name = name, + Description = description, + File = image.Stream, + Tags = string.Join(", ", tags) + }; + + return await client.ApiClient.CreateGuildStickerAsync(apiArgs, guild.Id, options).ConfigureAwait(false); + } + + public static async Task CreateStickerAsync(BaseDiscordClient client, IGuild guild, string name, string description, IEnumerable tags, + Stream file, string filename, RequestOptions options = null) + { + Preconditions.NotNull(name, nameof(name)); + Preconditions.NotNull(description, nameof(description)); + Preconditions.NotNull(file, nameof(file)); + Preconditions.NotNull(filename, nameof(filename)); + + Preconditions.AtLeast(name.Length, 2, nameof(name)); + Preconditions.AtLeast(description.Length, 2, nameof(description)); + + Preconditions.AtMost(name.Length, 30, nameof(name)); + Preconditions.AtMost(description.Length, 100, nameof(name)); + + var apiArgs = new CreateStickerParams() + { + Name = name, + Description = description, + File = file, + Tags = string.Join(", ", tags), + FileName = filename + }; + + return await client.ApiClient.CreateGuildStickerAsync(apiArgs, guild.Id, options).ConfigureAwait(false); + } + + public static async Task ModifyStickerAsync(BaseDiscordClient client, ulong guildId, ISticker sticker, Action func, + RequestOptions options = null) + { + if (func == null) + throw new ArgumentNullException(paramName: nameof(func)); + + var props = new StickerProperties(); + func(props); + + var apiArgs = new ModifyStickerParams() + { + Description = props.Description, + Name = props.Name, + Tags = props.Tags.IsSpecified ? + string.Join(", ", props.Tags.Value) : + Optional.Unspecified + }; + + return await client.ApiClient.ModifyStickerAsync(apiArgs, guildId, sticker.Id, options).ConfigureAwait(false); + } + + public static async Task DeleteStickerAsync(BaseDiscordClient client, ulong guildId, ISticker sticker, RequestOptions options = null) + => await client.ApiClient.DeleteStickerAsync(guildId, sticker.Id, options).ConfigureAwait(false); + #endregion + + #region Events + + public static async Task> GetEventUsersAsync(BaseDiscordClient client, IGuildScheduledEvent guildEvent, int limit = 100, RequestOptions options = null) + { + var models = await client.ApiClient.GetGuildScheduledEventUsersAsync(guildEvent.Id, guildEvent.Guild.Id, limit, options).ConfigureAwait(false); + + return models.Select(x => RestUser.Create(client, guildEvent.Guild, x)).ToImmutableArray(); + } + + public static IAsyncEnumerable> GetEventUsersAsync(BaseDiscordClient client, IGuildScheduledEvent guildEvent, + ulong? fromUserId, int? limit, RequestOptions options) + { + return new PagedAsyncEnumerable( + DiscordConfig.MaxGuildEventUsersPerBatch, + async (info, ct) => + { + var args = new GetEventUsersParams + { + Limit = info.PageSize, + RelativeDirection = Direction.After, + }; + if (info.Position != null) + args.RelativeUserId = info.Position.Value; + var models = await client.ApiClient.GetGuildScheduledEventUsersAsync(guildEvent.Id, guildEvent.Guild.Id, args, options).ConfigureAwait(false); + return models + .Select(x => RestUser.Create(client, guildEvent.Guild, x)) + .ToImmutableArray(); + }, + nextPage: (info, lastPage) => + { + if (lastPage.Count != DiscordConfig.MaxGuildEventUsersPerBatch) + return false; + info.Position = lastPage.Max(x => x.Id); + return true; + }, + start: fromUserId, + count: limit + ); + } + + public static IAsyncEnumerable> GetEventUsersAsync(BaseDiscordClient client, IGuildScheduledEvent guildEvent, + ulong? fromUserId, Direction dir, int limit, RequestOptions options = null) + { + if (dir == Direction.Around && limit > DiscordConfig.MaxMessagesPerBatch) + { + int around = limit / 2; + if (fromUserId.HasValue) + return GetEventUsersAsync(client, guildEvent, fromUserId.Value + 1, Direction.Before, around + 1, options) //Need to include the message itself + .Concat(GetEventUsersAsync(client, guildEvent, fromUserId, Direction.After, around, options)); + else //Shouldn't happen since there's no public overload for ulong? and Direction + return GetEventUsersAsync(client, guildEvent, null, Direction.Before, around + 1, options); + } + + return new PagedAsyncEnumerable( + DiscordConfig.MaxGuildEventUsersPerBatch, + async (info, ct) => + { + var args = new GetEventUsersParams + { + RelativeDirection = dir, + Limit = info.PageSize + }; + if (info.Position != null) + args.RelativeUserId = info.Position.Value; + + var models = await client.ApiClient.GetGuildScheduledEventUsersAsync(guildEvent.Id, guildEvent.Guild.Id, args, options).ConfigureAwait(false); + var builder = ImmutableArray.CreateBuilder(); + foreach (var model in models) + { + builder.Add(RestUser.Create(client, guildEvent.Guild, model)); + } + return builder.ToImmutable(); + }, + nextPage: (info, lastPage) => + { + if (lastPage.Count != DiscordConfig.MaxGuildEventUsersPerBatch) + return false; + if (dir == Direction.Before) + info.Position = lastPage.Min(x => x.Id); + else + info.Position = lastPage.Max(x => x.Id); + return true; + }, + start: fromUserId, + count: limit + ); + } + + public static async Task ModifyGuildEventAsync(BaseDiscordClient client, Action func, + IGuildScheduledEvent guildEvent, RequestOptions options = null) + { + var args = new GuildScheduledEventsProperties(); + + func(args); + + if (args.Status.IsSpecified) + { + switch (args.Status.Value) + { + case GuildScheduledEventStatus.Active when guildEvent.Status != GuildScheduledEventStatus.Scheduled: + case GuildScheduledEventStatus.Completed when guildEvent.Status != GuildScheduledEventStatus.Active: + case GuildScheduledEventStatus.Cancelled when guildEvent.Status != GuildScheduledEventStatus.Scheduled: + throw new ArgumentException($"Cannot set event to {args.Status.Value} when events status is {guildEvent.Status}"); + } + } + + if (args.Type.IsSpecified) + { + // taken from https://discord.com/developers/docs/resources/guild-scheduled-event#modify-guild-scheduled-event + switch (args.Type.Value) + { + case GuildScheduledEventType.External: + if (!args.Location.IsSpecified) + throw new ArgumentException("Location must be specified for external events."); + if (!args.EndTime.IsSpecified) + throw new ArgumentException("End time must be specified for external events."); + if (!args.ChannelId.IsSpecified) + throw new ArgumentException("Channel id must be set to null!"); + if (args.ChannelId.Value != null) + throw new ArgumentException("Channel id must be set to null!"); + break; + } + } + + var apiArgs = new ModifyGuildScheduledEventParams() + { + ChannelId = args.ChannelId, + Description = args.Description, + EndTime = args.EndTime, + Name = args.Name, + PrivacyLevel = args.PrivacyLevel, + StartTime = args.StartTime, + Status = args.Status, + Type = args.Type + }; + + if(args.Location.IsSpecified) + { + apiArgs.EntityMetadata = new API.GuildScheduledEventEntityMetadata() + { + Location = args.Location, + }; + } + + return await client.ApiClient.ModifyGuildScheduledEventAsync(apiArgs, guildEvent.Id, guildEvent.Guild.Id, options).ConfigureAwait(false); + } + + public static async Task GetGuildEventAsync(BaseDiscordClient client, ulong id, IGuild guild, RequestOptions options = null) + { + var model = await client.ApiClient.GetGuildScheduledEventAsync(id, guild.Id, options).ConfigureAwait(false); + + if (model == null) + return null; + + return RestGuildEvent.Create(client, guild, model); + } + + public static async Task> GetGuildEventsAsync(BaseDiscordClient client, IGuild guild, RequestOptions options = null) + { + var models = await client.ApiClient.ListGuildScheduledEventsAsync(guild.Id, options).ConfigureAwait(false); + + return models.Select(x => RestGuildEvent.Create(client, guild, x)).ToImmutableArray(); + } + + public static async Task CreateGuildEventAsync(BaseDiscordClient client, IGuild guild, + string name, + GuildScheduledEventPrivacyLevel privacyLevel, + DateTimeOffset startTime, + GuildScheduledEventType type, + string description = null, + DateTimeOffset? endTime = null, + ulong? channelId = null, + string location = null, + RequestOptions options = null) + { + if(location != null) + { + Preconditions.AtMost(location.Length, 100, nameof(location)); + } + + switch (type) + { + case GuildScheduledEventType.Stage or GuildScheduledEventType.Voice when channelId == null: + throw new ArgumentException($"{nameof(channelId)} must not be null when type is {type}", nameof(channelId)); + case GuildScheduledEventType.External when channelId != null: + throw new ArgumentException($"{nameof(channelId)} must be null when using external event type", nameof(channelId)); + case GuildScheduledEventType.External when location == null: + throw new ArgumentException($"{nameof(location)} must not be null when using external event type", nameof(location)); + case GuildScheduledEventType.External when endTime == null: + throw new ArgumentException($"{nameof(endTime)} must not be null when using external event type", nameof(endTime)); + } + + if (startTime <= DateTimeOffset.Now) + throw new ArgumentOutOfRangeException(nameof(startTime), "The start time for an event cannot be in the past"); + + if (endTime != null && endTime <= startTime) + throw new ArgumentOutOfRangeException(nameof(endTime), $"{nameof(endTime)} cannot be before the start time"); + + var apiArgs = new CreateGuildScheduledEventParams() + { + ChannelId = channelId ?? Optional.Unspecified, + Description = description ?? Optional.Unspecified, + EndTime = endTime ?? Optional.Unspecified, + Name = name, + PrivacyLevel = privacyLevel, + StartTime = startTime, + Type = type + }; + + if(location != null) + { + apiArgs.EntityMetadata = new API.GuildScheduledEventEntityMetadata() + { + Location = location + }; + } + + var model = await client.ApiClient.CreateGuildScheduledEventAsync(apiArgs, guild.Id, options).ConfigureAwait(false); + + return RestGuildEvent.Create(client, guild, client.CurrentUser, model); + } + + public static async Task DeleteEventAsync(BaseDiscordClient client, IGuildScheduledEvent guildEvent, RequestOptions options = null) + { + await client.ApiClient.DeleteGuildScheduledEventAsync(guildEvent.Id, guildEvent.Guild.Id, options).ConfigureAwait(false); + } + + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestBan.cs b/src/Discord.Net.Rest/Entities/Guilds/RestBan.cs index ec8f60ae5..d77d3b626 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/RestBan.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/RestBan.cs @@ -9,6 +9,7 @@ namespace Discord.Rest [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class RestBan : IBan { + #region RestBan /// /// Gets the banned user. /// @@ -37,9 +38,11 @@ internal static RestBan Create(BaseDiscordClient client, Model model) /// public override string ToString() => User.ToString(); private string DebuggerDisplay => $"{User}: {Reason}"; +#endregion - //IBan + #region IBan /// IUser IBan.User => User; + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs index ea703a26a..9b0b66633 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using WidgetModel = Discord.API.GuildWidget; using Model = Discord.API.Guild; +using System.IO; namespace Discord.Rest { @@ -17,9 +18,10 @@ namespace Discord.Rest [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class RestGuild : RestEntity, IGuild, IUpdateable { + #region RestGuild private ImmutableDictionary _roles; private ImmutableArray _emotes; - private ImmutableArray _features; + private ImmutableArray _stickers; /// public string Name { get; private set; } @@ -83,9 +85,14 @@ public class RestGuild : RestEntity, IGuild, IUpdateable public int? ApproximateMemberCount { get; private set; } /// public int? ApproximatePresenceCount { get; private set; } - + /// + public NsfwLevel NsfwLevel { get; private set; } + /// + public bool IsBoostProgressBarEnabled { get; private set; } /// public CultureInfo PreferredCulture { get; private set; } + /// + public GuildFeatures Features { get; private set; } /// public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); @@ -97,7 +104,7 @@ public class RestGuild : RestEntity, IGuild, IUpdateable /// public string DiscoverySplashUrl => CDN.GetGuildDiscoverySplashUrl(Id, DiscoverySplashId); /// - public string BannerUrl => CDN.GetGuildBannerUrl(Id, BannerId); + public string BannerUrl => CDN.GetGuildBannerUrl(Id, BannerId, ImageFormat.Auto); /// /// Gets the built-in role containing all users in this guild. @@ -110,8 +117,7 @@ public class RestGuild : RestEntity, IGuild, IUpdateable public IReadOnlyCollection Roles => _roles.ToReadOnlyCollection(); /// public IReadOnlyCollection Emotes => _emotes; - /// - public IReadOnlyCollection Features => _features; + public IReadOnlyCollection Stickers => _stickers; internal RestGuild(BaseDiscordClient client, ulong id) : base(client, id) @@ -151,6 +157,7 @@ internal void Update(Model model) SystemChannelFlags = model.SystemChannelFlags; Description = model.Description; PremiumSubscriptionCount = model.PremiumSubscriptionCount.GetValueOrDefault(); + NsfwLevel = model.NsfwLevel; if (model.MaxPresences.IsSpecified) MaxPresences = model.MaxPresences.Value ?? 25000; if (model.MaxMembers.IsSpecified) @@ -163,6 +170,8 @@ internal void Update(Model model) ApproximateMemberCount = model.ApproximateMemberCount.Value; if (model.ApproximatePresenceCount.IsSpecified) ApproximatePresenceCount = model.ApproximatePresenceCount.Value; + if (model.IsBoostProgressBarEnabled.IsSpecified) + IsBoostProgressBarEnabled = model.IsBoostProgressBarEnabled.Value; if (model.Emojis != null) { @@ -174,10 +183,7 @@ internal void Update(Model model) else _emotes = ImmutableArray.Create(); - if (model.Features != null) - _features = model.Features.ToImmutableArray(); - else - _features = ImmutableArray.Create(); + Features = model.Features; var roles = ImmutableDictionary.CreateBuilder(); if (model.Roles != null) @@ -187,6 +193,23 @@ internal void Update(Model model) } _roles = roles.ToImmutable(); + if (model.Stickers != null) + { + var stickers = ImmutableArray.CreateBuilder(); + for (int i = 0; i < model.Stickers.Length; i++) + { + var sticker = model.Stickers[i]; + + var entity = CustomSticker.Create(Discord, sticker, this, sticker.User.IsSpecified ? sticker.User.Value.Id : null); + + stickers.Add(entity); + } + + _stickers = stickers.ToImmutable(); + } + else + _stickers = ImmutableArray.Create(); + Available = true; } internal void Update(WidgetModel model) @@ -194,8 +217,9 @@ internal void Update(WidgetModel model) WidgetChannelId = model.ChannelId; IsWidgetEnabled = model.Enabled; } + #endregion - //General + #region General /// public async Task UpdateAsync(RequestOptions options = null) => Update(await Discord.ApiClient.GetGuildAsync(Id, false, options).ConfigureAwait(false)); @@ -254,9 +278,44 @@ public async Task ReorderRolesAsync(IEnumerable args, Req /// public Task LeaveAsync(RequestOptions options = null) => GuildHelper.LeaveAsync(this, Discord, options); + #endregion + + #region Interactions + /// + /// Deletes all slash commands in the current guild. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous delete operation. + /// + public Task DeleteSlashCommandsAsync(RequestOptions options = null) + => InteractionHelper.DeleteAllGuildCommandsAsync(Discord, Id, options); + + /// + /// Gets a collection of slash commands created by the current user in this guild. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection of + /// slash commands created by the current user. + /// + public Task> GetSlashCommandsAsync(RequestOptions options = null) + => GuildHelper.GetSlashCommandsAsync(this, Discord, options); + + /// + /// Gets a slash command in the current guild. + /// + /// The unique identifier of the slash command. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a + /// slash command created by the current user. + /// + public Task GetSlashCommandAsync(ulong id, RequestOptions options = null) + => GuildHelper.GetSlashCommandAsync(this, id, Discord, options); + #endregion - //Bans - //Bans + #region Bans /// /// Gets a collection of all users banned in this guild. /// @@ -304,8 +363,9 @@ public Task RemoveBanAsync(IUser user, RequestOptions options = null) /// public Task RemoveBanAsync(ulong userId, RequestOptions options = null) => GuildHelper.RemoveBanAsync(this, Discord, userId, options); + #endregion - //Channels + #region Channels /// /// Gets a collection of all channels in this guild. /// @@ -358,6 +418,35 @@ public async Task> GetTextChannelsAsync(Req return channels.OfType().ToImmutableArray(); } + /// + /// Gets a thread channel in this guild. + /// + /// The snowflake identifier for the thread channel. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains the thread channel associated + /// with the specified ; if none is found. + /// + public async Task GetThreadChannelAsync(ulong id, RequestOptions options = null) + { + var channel = await GuildHelper.GetChannelAsync(this, Discord, id, options).ConfigureAwait(false); + return channel as RestThreadChannel; + } + + /// + /// Gets a collection of all thread in this guild. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection of + /// threads found within this guild. + /// + public async Task> GetThreadChannelsAsync(RequestOptions options = null) + { + var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); + return channels.OfType().ToImmutableArray(); + } + /// /// Gets a voice channel in this guild. /// @@ -386,6 +475,34 @@ public async Task> GetVoiceChannelsAsync(R var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); return channels.OfType().ToImmutableArray(); } + /// + /// Gets a stage channel in this guild + /// + /// The snowflake identifier for the stage channel. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains the stage channel associated + /// with the specified ; if none is found. + /// + public async Task GetStageChannelAsync(ulong id, RequestOptions options = null) + { + var channel = await GuildHelper.GetChannelAsync(this, Discord, id, options).ConfigureAwait(false); + return channel as RestStageChannel; + } + + /// + /// Gets a collection of all stage channels in this guild. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection of + /// stage channels found within this guild. + /// + public async Task> GetStageChannelsAsync(RequestOptions options = null) + { + var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); + return channels.OfType().ToImmutableArray(); + } /// /// Gets a collection of all category channels in this guild. @@ -460,7 +577,7 @@ public async Task GetWidgetChannelAsync(RequestOptions options /// The options to be used when sending the request. /// /// A task that represents the asynchronous get operation. The task result contains the text channel - /// where guild notices such as welcome messages and boost events are poste; if none is found. + /// where guild notices such as welcome messages and boost events are post; if none is found. /// public async Task GetSystemChannelAsync(RequestOptions options = null) { @@ -493,11 +610,11 @@ public async Task GetRulesChannelAsync(RequestOptions options = } /// - /// Gets the text channel channel where admins and moderators of Community guilds receive notices from Discord. + /// Gets the text channel where admins and moderators of Community guilds receive notices from Discord. /// /// The options to be used when sending the request. /// - /// A task that represents the asynchronous get operation. The task result contains the text channel channel where + /// A task that represents the asynchronous get operation. The task result contains the text channel where /// admins and moderators of Community guilds receive notices from Discord; if none is set. /// public async Task GetPublicUpdatesChannelAsync(RequestOptions options = null) @@ -549,6 +666,18 @@ public Task CreateTextChannelAsync(string name, Action CreateVoiceChannelAsync(string name, Action func = null, RequestOptions options = null) => GuildHelper.CreateVoiceChannelAsync(this, Discord, name, options, func); /// + /// Creates a new stage channel in this guild. + /// + /// The new name for the stage channel. + /// The delegate containing the properties to be applied to the channel upon its creation. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the newly created + /// stage channel. + /// + public Task CreateStageChannelAsync(string name, Action func = null, RequestOptions options = null) + => GuildHelper.CreateStageChannelAsync(this, Discord, name, options, func); + /// /// Creates a category channel with the provided name. /// /// The name of the new channel. @@ -571,14 +700,16 @@ public Task CreateCategoryChannelAsync(string name, Action< /// public Task> GetVoiceRegionsAsync(RequestOptions options = null) => GuildHelper.GetVoiceRegionsAsync(this, Discord, options); + #endregion - //Integrations + #region Integrations public Task> GetIntegrationsAsync(RequestOptions options = null) => GuildHelper.GetIntegrationsAsync(this, Discord, options); public Task CreateIntegrationAsync(ulong id, string type, RequestOptions options = null) => GuildHelper.CreateIntegrationAsync(this, Discord, id, type, options); + #endregion - //Invites + #region Invites /// /// Gets a collection of all invites in this guild. /// @@ -598,8 +729,9 @@ public Task> GetInvitesAsync(RequestOpti /// public Task GetVanityInviteAsync(RequestOptions options = null) => GuildHelper.GetVanityInviteAsync(this, Discord, options); + #endregion - //Roles + #region Roles /// /// Gets a role in this guild. /// @@ -639,8 +771,9 @@ public RestRole GetRole(ulong id) _roles = _roles.Add(role.Id, role); return role; } + #endregion - //Users + #region Users /// /// Gets a collection of all users in this guild. /// @@ -734,8 +867,9 @@ public Task PruneUsersAsync(int days = 30, bool simulate = false, RequestOp /// public Task> SearchUsersAsync(string query, int limit = DiscordConfig.MaxUsersPerBatch, RequestOptions options = null) => GuildHelper.SearchUsersAsync(this, Discord, query, limit, options); + #endregion - //Audit logs + #region Audit logs /// /// Gets the specified number of audit log entries for this guild. /// @@ -750,8 +884,9 @@ public Task> SearchUsersAsync(string query, i /// public IAsyncEnumerable> GetAuditLogsAsync(int limit, RequestOptions options = null, ulong? beforeId = null, ulong? userId = null, ActionType? actionType = null) => GuildHelper.GetAuditLogsAsync(this, Discord, beforeId, limit, options, userId: userId, actionType: actionType); + #endregion - //Webhooks + #region Webhooks /// /// Gets a webhook found within this guild. /// @@ -774,6 +909,59 @@ public Task GetWebhookAsync(ulong id, RequestOptions options = null /// public Task> GetWebhooksAsync(RequestOptions options = null) => GuildHelper.GetWebhooksAsync(this, Discord, options); + #endregion + + #region Interactions + /// + /// Gets this guilds slash commands + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection + /// of application commands found within the guild. + /// + public async Task> GetApplicationCommandsAsync (RequestOptions options = null) + => await ClientHelper.GetGuildApplicationCommandsAsync(Discord, Id, options).ConfigureAwait(false); + /// + /// Gets an application command within this guild with the specified id. + /// + /// The id of the application command to get. + /// The options to be used when sending the request. + /// + /// A ValueTask that represents the asynchronous get operation. The task result contains a + /// if found, otherwise . + /// + public async Task GetApplicationCommandAsync(ulong id, RequestOptions options = null) + => await ClientHelper.GetGuildApplicationCommandAsync(Discord, id, Id, options); + /// + /// Creates an application command within this guild. + /// + /// The properties to use when creating the command. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the command that was created. + /// + public async Task CreateApplicationCommandAsync(ApplicationCommandProperties properties, RequestOptions options = null) + { + var model = await InteractionHelper.CreateGuildCommandAsync(Discord, Id, properties, options); + + return RestGuildCommand.Create(Discord, model, Id); + } + /// + /// Overwrites the application commands within this guild. + /// + /// A collection of properties to use when creating the commands. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains a collection of commands that was created. + /// + public async Task> BulkOverwriteApplicationCommandsAsync(ApplicationCommandProperties[] properties, + RequestOptions options = null) + { + var models = await InteractionHelper.BulkOverwriteGuildCommandsAsync(Discord, Id, properties, options); + + return models.Select(x => RestGuildCommand.Create(Discord, x, Id)).ToImmutableArray(); + } /// /// Returns the name of the guild. @@ -783,8 +971,9 @@ public Task> GetWebhooksAsync(RequestOptions op /// public override string ToString() => Name; private string DebuggerDisplay => $"{Name} ({Id})"; + #endregion - //Emotes + #region Emotes /// public Task> GetEmotesAsync(RequestOptions options = null) => GuildHelper.GetEmotesAsync(this, Discord, options); @@ -798,11 +987,188 @@ public Task GetEmoteAsync(ulong id, RequestOptions options = null) /// is . public Task ModifyEmoteAsync(GuildEmote emote, Action func, RequestOptions options = null) => GuildHelper.ModifyEmoteAsync(this, Discord, emote.Id, func, options); + /// + /// Moves the user to the voice channel. + /// + /// The user to move. + /// the channel where the user gets moved to. + /// A task that represents the asynchronous operation for moving a user. + public Task MoveAsync(IGuildUser user, IVoiceChannel targetChannel) + => user.ModifyAsync(x => x.Channel = new Optional(targetChannel)); /// public Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null) => GuildHelper.DeleteEmoteAsync(this, Discord, emote.Id, options); + #endregion + + #region Stickers + /// + /// Creates a new sticker in this guild. + /// + /// The name of the sticker. + /// The description of the sticker. + /// The tags of the sticker. + /// The image of the new emote. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the created sticker. + /// + public async Task CreateStickerAsync(string name, string description, IEnumerable tags, Image image, RequestOptions options = null) + { + var model = await GuildHelper.CreateStickerAsync(Discord, this, name, description, tags, image, options).ConfigureAwait(false); + + return CustomSticker.Create(Discord, model, this, model.User.IsSpecified ? model.User.Value.Id : null); + } + /// + /// Creates a new sticker in this guild + /// + /// The name of the sticker. + /// The description of the sticker. + /// The tags of the sticker. + /// The path of the file to upload. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the created sticker. + /// + public Task CreateStickerAsync(string name, string description, IEnumerable tags, string path, + RequestOptions options = null) + { + var fs = File.OpenRead(path); + return CreateStickerAsync(name, description, tags, fs, Path.GetFileName(fs.Name), options); + } + /// + /// Creates a new sticker in this guild + /// + /// The name of the sticker. + /// The description of the sticker. + /// The tags of the sticker. + /// The stream containing the file data. + /// The name of the file with the extension, ex: image.png. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the created sticker. + /// + public async Task CreateStickerAsync(string name, string description, IEnumerable tags, Stream stream, + string filename, RequestOptions options = null) + { + var model = await GuildHelper.CreateStickerAsync(Discord, this, name, description, tags, stream, filename, options).ConfigureAwait(false); + + return CustomSticker.Create(Discord, model, this, model.User.IsSpecified ? model.User.Value.Id : null); + } + /// + /// Gets a specific sticker within this guild. + /// + /// The id of the sticker to get. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains the sticker found with the + /// specified ; if none is found. + /// + public async Task GetStickerAsync(ulong id, RequestOptions options = null) + { + var model = await Discord.ApiClient.GetGuildStickerAsync(Id, id, options).ConfigureAwait(false); + + if (model == null) + return null; + + return CustomSticker.Create(Discord, model, this, model.User.IsSpecified ? model.User.Value.Id : null); + } + /// + /// Gets a collection of all stickers within this guild. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection + /// of stickers found within the guild. + /// + public async Task> GetStickersAsync(RequestOptions options = null) + { + var models = await Discord.ApiClient.ListGuildStickersAsync(Id, options).ConfigureAwait(false); + + if (models.Length == 0) + return null; - //IGuild + List stickers = new List(); + + foreach(var model in models) + { + var entity = CustomSticker.Create(Discord, model, this, model.User.IsSpecified ? model.User.Value.Id : null); + stickers.Add(entity); + } + + return stickers.ToImmutableArray(); + } + /// + /// Deletes a sticker within this guild. + /// + /// The sticker to delete. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous removal operation. + /// + public Task DeleteStickerAsync(CustomSticker sticker, RequestOptions options = null) + => sticker.DeleteAsync(options); + #endregion + + #region Guild Events + + /// + /// Gets an event within this guild. + /// + /// The snowflake identifier for the event. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. + /// + public Task GetEventAsync(ulong id, RequestOptions options = null) + => GuildHelper.GetGuildEventAsync(Discord, id, this, options); + + /// + /// Gets all active events within this guild. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. + /// + public Task> GetEventsAsync(RequestOptions options = null) + => GuildHelper.GetGuildEventsAsync(Discord, this, options); + + /// + /// Creates an event within this guild. + /// + /// The name of the event. + /// The privacy level of the event. + /// The start time of the event. + /// The type of the event. + /// The description of the event. + /// The end time of the event. + /// + /// The channel id of the event. + /// + /// The event must have a type of or + /// in order to use this property. + /// + /// + /// A collection of speakers for the event. + /// The location of the event; links are supported + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous create operation. + /// + public Task CreateEventAsync( + string name, + DateTimeOffset startTime, + GuildScheduledEventType type, + GuildScheduledEventPrivacyLevel privacyLevel = GuildScheduledEventPrivacyLevel.Private, + string description = null, + DateTimeOffset? endTime = null, + ulong? channelId = null, + string location = null, + RequestOptions options = null) + => GuildHelper.CreateGuildEventAsync(Discord, this, name, privacyLevel, startTime, type, description, endTime, channelId, location, options); + + #endregion + + #region IGuild /// bool IGuild.Available => Available; /// @@ -812,6 +1178,20 @@ public Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null) /// IReadOnlyCollection IGuild.Roles => Roles; + IReadOnlyCollection IGuild.Stickers => Stickers; + + /// + async Task IGuild.CreateEventAsync(string name, DateTimeOffset startTime, GuildScheduledEventType type, GuildScheduledEventPrivacyLevel privacyLevel, string description, DateTimeOffset? endTime, ulong? channelId, string location, RequestOptions options) + => await CreateEventAsync(name, startTime, type, privacyLevel, description, endTime, channelId, location, options).ConfigureAwait(false); + + /// + async Task IGuild.GetEventAsync(ulong id, RequestOptions options) + => await GetEventAsync(id, options).ConfigureAwait(false); + + /// + async Task> IGuild.GetEventsAsync(RequestOptions options) + => await GetEventsAsync(options).ConfigureAwait(false); + /// async Task> IGuild.GetBansAsync(RequestOptions options) => await GetBansAsync(options).ConfigureAwait(false); @@ -855,6 +1235,22 @@ async Task IGuild.GetTextChannelAsync(ulong id, CacheMode mode, Re return null; } /// + async Task IGuild.GetThreadChannelAsync(ulong id, CacheMode mode, RequestOptions options) + { + if (mode == CacheMode.AllowDownload) + return await GetThreadChannelAsync(id, options).ConfigureAwait(false); + else + return null; + } + /// + async Task> IGuild.GetThreadChannelsAsync(CacheMode mode, RequestOptions options) + { + if (mode == CacheMode.AllowDownload) + return await GetThreadChannelsAsync(options).ConfigureAwait(false); + else + return null; + } + /// async Task> IGuild.GetVoiceChannelsAsync(CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) @@ -871,6 +1267,22 @@ async Task> IGuild.GetCategoriesAsync(Cach return null; } /// + async Task IGuild.GetStageChannelAsync(ulong id, CacheMode mode, RequestOptions options ) + { + if (mode == CacheMode.AllowDownload) + return await GetStageChannelAsync(id, options).ConfigureAwait(false); + else + return null; + } + /// + async Task> IGuild.GetStageChannelsAsync(CacheMode mode, RequestOptions options) + { + if (mode == CacheMode.AllowDownload) + return await GetStageChannelsAsync(options).ConfigureAwait(false); + else + return null; + } + /// async Task IGuild.GetVoiceChannelAsync(ulong id, CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) @@ -933,6 +1345,9 @@ async Task IGuild.CreateTextChannelAsync(string name, Action IGuild.CreateVoiceChannelAsync(string name, Action func, RequestOptions options) => await CreateVoiceChannelAsync(name, func, options).ConfigureAwait(false); /// + async Task IGuild.CreateStageChannelAsync(string name, Action func, RequestOptions options) + => await CreateStageChannelAsync(name, func, options).ConfigureAwait(false); + /// async Task IGuild.CreateCategoryAsync(string name, Action func, RequestOptions options) => await CreateCategoryChannelAsync(name, func, options).ConfigureAwait(false); @@ -968,6 +1383,13 @@ async Task IGuild.CreateRoleAsync(string name, GuildPermissions? permissi async Task IGuild.AddGuildUserAsync(ulong userId, string accessToken, Action func, RequestOptions options) => await AddGuildUserAsync(userId, accessToken, func, options); + /// + /// Disconnects the user from its current voice channel + /// + /// The user to disconnect. + /// A task that represents the asynchronous operation for disconnecting a user. + async Task IGuild.DisconnectAsync(IGuildUser user) => await user.ModifyAsync(x => x.Channel = new Optional()); + /// async Task IGuild.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) { @@ -1028,5 +1450,54 @@ async Task IGuild.GetWebhookAsync(ulong id, RequestOptions options) /// async Task> IGuild.GetWebhooksAsync(RequestOptions options) => await GetWebhooksAsync(options).ConfigureAwait(false); + /// + async Task> IGuild.GetApplicationCommandsAsync (RequestOptions options) + => await GetApplicationCommandsAsync(options).ConfigureAwait(false); + /// + async Task IGuild.CreateStickerAsync(string name, string description, IEnumerable tags, Image image, RequestOptions options) + => await CreateStickerAsync(name, description, tags, image, options); + /// + async Task IGuild.CreateStickerAsync(string name, string description, IEnumerable tags, Stream stream, string filename, RequestOptions options) + => await CreateStickerAsync(name, description, tags, stream, filename, options); + /// + async Task IGuild.CreateStickerAsync(string name, string description, IEnumerable tags, string path, RequestOptions options) + => await CreateStickerAsync(name, description, tags, path, options); + /// + async Task IGuild.GetStickerAsync(ulong id, CacheMode mode, RequestOptions options) + { + if (mode != CacheMode.AllowDownload) + return null; + + return await GetStickerAsync(id, options); + } + /// + async Task> IGuild.GetStickersAsync(CacheMode mode, RequestOptions options) + { + if (mode != CacheMode.AllowDownload) + return null; + + return await GetStickersAsync(options); + } + /// + Task IGuild.DeleteStickerAsync(ICustomSticker sticker, RequestOptions options) + => sticker.DeleteAsync(); + /// + async Task IGuild.CreateApplicationCommandAsync(ApplicationCommandProperties properties, RequestOptions options) + => await CreateApplicationCommandAsync(properties, options); + /// + async Task> IGuild.BulkOverwriteApplicationCommandsAsync(ApplicationCommandProperties[] properties, + RequestOptions options) + => await BulkOverwriteApplicationCommandsAsync(properties, options); + /// + async Task IGuild.GetApplicationCommandAsync(ulong id, CacheMode mode, RequestOptions options) + { + if (mode == CacheMode.AllowDownload) + { + return await GetApplicationCommandAsync(id, options); + } + else + return null; + } + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuildEvent.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuildEvent.cs new file mode 100644 index 000000000..d3ec11fc6 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuildEvent.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Model = Discord.API.GuildScheduledEvent; + +namespace Discord.Rest +{ + public class RestGuildEvent : RestEntity, IGuildScheduledEvent + { + /// + public IGuild Guild { get; private set; } + + /// + public ulong? ChannelId { get; private set; } + + /// + public IUser Creator { get; private set; } + + /// + public ulong CreatorId { get; private set; } + + /// + public string Name { get; private set; } + + /// + public string Description { get; private set; } + + /// + public DateTimeOffset StartTime { get; private set; } + + /// + public DateTimeOffset? EndTime { get; private set; } + + /// + public GuildScheduledEventPrivacyLevel PrivacyLevel { get; private set; } + + /// + public GuildScheduledEventStatus Status { get; private set; } + + /// + public GuildScheduledEventType Type { get; private set; } + + /// + public ulong? EntityId { get; private set; } + + /// + public string Location { get; private set; } + + /// + public int? UserCount { get; private set; } + + internal RestGuildEvent(BaseDiscordClient client, IGuild guild, ulong id) + : base(client, id) + { + Guild = guild; + } + + internal static RestGuildEvent Create(BaseDiscordClient client, IGuild guild, Model model) + { + var entity = new RestGuildEvent(client, guild, model.Id); + entity.Update(model); + return entity; + } + + internal static RestGuildEvent Create(BaseDiscordClient client, IGuild guild, IUser creator, Model model) + { + var entity = new RestGuildEvent(client, guild, model.Id); + entity.Update(model, creator); + return entity; + } + + internal void Update(Model model, IUser creator) + { + Update(model); + Creator = creator; + CreatorId = creator.Id; + } + + internal void Update(Model model) + { + if (model.Creator.IsSpecified) + { + Creator = RestUser.Create(Discord, model.Creator.Value); + } + + CreatorId = model.CreatorId.ToNullable() ?? 0; // should be changed? + ChannelId = model.ChannelId.IsSpecified ? model.ChannelId.Value : null; + Name = model.Name; + Description = model.Description.GetValueOrDefault(); + StartTime = model.ScheduledStartTime; + EndTime = model.ScheduledEndTime; + PrivacyLevel = model.PrivacyLevel; + Status = model.Status; + Type = model.EntityType; + EntityId = model.EntityId; + Location = model.EntityMetadata?.Location.GetValueOrDefault(); + UserCount = model.UserCount.ToNullable(); + } + + /// + public Task StartAsync(RequestOptions options = null) + => ModifyAsync(x => x.Status = GuildScheduledEventStatus.Active); + + /// + public Task EndAsync(RequestOptions options = null) + => ModifyAsync(x => x.Status = Status == GuildScheduledEventStatus.Scheduled + ? GuildScheduledEventStatus.Cancelled + : GuildScheduledEventStatus.Completed); + + /// + public Task DeleteAsync(RequestOptions options = null) + => GuildHelper.DeleteEventAsync(Discord, this, options); + + /// + public async Task ModifyAsync(Action func, RequestOptions options = null) + { + var model = await GuildHelper.ModifyGuildEventAsync(Discord, func, this, options).ConfigureAwait(false); + Update(model); + } + + /// + /// Gets a collection of N users interested in the event. + /// + /// + /// + /// The returned collection is an asynchronous enumerable object; one must call + /// to access the individual messages as a + /// collection. + /// + /// This method will attempt to fetch all users that are interested in the event. + /// The library will attempt to split up the requests according to and . + /// In other words, if there are 300 users, and the constant + /// is 100, the request will be split into 3 individual requests; thus returning 3 individual asynchronous + /// responses, hence the need of flattening. + /// + /// The options to be used when sending the request. + /// + /// Paged collection of users. + /// + public IAsyncEnumerable> GetUsersAsync(RequestOptions options = null) + => GuildHelper.GetEventUsersAsync(Discord, this, null, null, options); + + /// + /// Gets a collection of N users interested in the event. + /// + /// + /// + /// The returned collection is an asynchronous enumerable object; one must call + /// to access the individual users as a + /// collection. + /// + /// + /// Do not fetch too many users at once! This may cause unwanted preemptive rate limit or even actual + /// rate limit, causing your bot to freeze! + /// + /// This method will attempt to fetch the number of users specified under around + /// the user depending on the . The library will + /// attempt to split up the requests according to your and + /// . In other words, should the user request 500 users, + /// and the constant is 100, the request will + /// be split into 5 individual requests; thus returning 5 individual asynchronous responses, hence the need + /// of flattening. + /// + /// The ID of the starting user to get the users from. + /// The direction of the users to be gotten from. + /// The numbers of users to be gotten from. + /// The options to be used when sending the request. + /// + /// Paged collection of users. + /// + public IAsyncEnumerable> GetUsersAsync(ulong fromUserId, Direction dir, int limit = DiscordConfig.MaxGuildEventUsersPerBatch, RequestOptions options = null) + => GuildHelper.GetEventUsersAsync(Discord, this, fromUserId, dir, limit, options); + + #region IGuildScheduledEvent + + /// + IAsyncEnumerable> IGuildScheduledEvent.GetUsersAsync(RequestOptions options) + => GetUsersAsync(options); + /// + IAsyncEnumerable> IGuildScheduledEvent.GetUsersAsync(ulong fromUserId, Direction dir, int limit, RequestOptions options) + => GetUsersAsync(fromUserId, dir, limit, options); + + #endregion + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestCommandBase.cs b/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestCommandBase.cs new file mode 100644 index 000000000..a9efb6de1 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestCommandBase.cs @@ -0,0 +1,345 @@ +using Discord.Net.Rest; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DataModel = Discord.API.ApplicationCommandInteractionData; +using Model = Discord.API.Interaction; + +namespace Discord.Rest +{ + /// + /// Represents a REST-based base command interaction. + /// + public class RestCommandBase : RestInteraction + { + /// + /// Gets the name of the invoked command. + /// + public string CommandName + => Data.Name; + + /// + /// Gets the id of the invoked command. + /// + public ulong CommandId + => Data.Id; + + /// + /// The data associated with this interaction. + /// + internal new RestCommandBaseData Data { get; private set; } + + + internal override bool _hasResponded { get; set; } + + private object _lock = new object(); + + internal RestCommandBase(DiscordRestClient client, Model model) + : base(client, model.Id) + { + } + + internal new static async Task CreateAsync(DiscordRestClient client, Model model) + { + var entity = new RestCommandBase(client, model); + await entity.UpdateAsync(client, model).ConfigureAwait(false); + return entity; + } + + internal override async Task UpdateAsync(DiscordRestClient client, Model model) + { + await base.UpdateAsync(client, model).ConfigureAwait(false); + } + + /// + /// Responds to an Interaction with type . + /// + /// The text of the message to be sent. + /// A array of embeds to send with this response. Max 10. + /// if the message should be read out by a text-to-speech reader, otherwise . + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . + /// The allowed mentions for this response. + /// The request options for this response. + /// A to be sent with this response. + /// A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + /// Message content is too long, length must be less or equal to . + /// The parameters provided were invalid or the token was invalid. + /// + /// A string that contains json to write back to the incoming http request. + /// + public override string Respond( + string text = null, + Embed[] embeds = null, + bool isTTS = false, + bool ephemeral = false, + AllowedMentions allowedMentions = null, + RequestOptions options = null, + MessageComponent component = null, + Embed embed = null) + { + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + if (!InteractionHelper.CanSendResponse(this)) + throw new TimeoutException($"Cannot respond to an interaction after {InteractionHelper.ResponseTimeLimit} seconds!"); + + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + + // check that user flag and user Id list are exclusive, same with role flag and role Id list + if (allowedMentions != null && allowedMentions.AllowedTypes.HasValue) + { + if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Users) && + allowedMentions.UserIds != null && allowedMentions.UserIds.Count > 0) + { + throw new ArgumentException("The Users flag is mutually exclusive with the list of User Ids.", nameof(allowedMentions)); + } + + if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Roles) && + allowedMentions.RoleIds != null && allowedMentions.RoleIds.Count > 0) + { + throw new ArgumentException("The Roles flag is mutually exclusive with the list of Role Ids.", nameof(allowedMentions)); + } + } + + var response = new API.InteractionResponse + { + Type = InteractionResponseType.ChannelMessageWithSource, + Data = new API.InteractionCallbackData + { + Content = text, + AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, + Embeds = embeds.Select(x => x.ToModel()).ToArray(), + TTS = isTTS, + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified, + Flags = ephemeral ? MessageFlags.Ephemeral : Optional.Unspecified + } + }; + + lock (_lock) + { + if (_hasResponded) + { + throw new InvalidOperationException("Cannot respond twice to the same interaction"); + } + } + + lock (_lock) + { + _hasResponded = true; + } + + return SerializePayload(response); + } + + /// + /// Sends a followup message for this interaction. + /// + /// The text of the message to be sent. + /// A array of embeds to send with this response. Max 10. + /// if the message should be read out by a text-to-speech reader, otherwise . + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . + /// The allowed mentions for this response. + /// The request options for this response. + /// A to be sent with this response. + /// A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + /// + /// The sent message. + /// + public override async Task FollowupAsync( + string text = null, + Embed[] embeds = null, + bool isTTS = false, + bool ephemeral = false, + AllowedMentions allowedMentions = null, + RequestOptions options = null, + MessageComponent component = null, + Embed embed = null) + { + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + + var args = new API.Rest.CreateWebhookMessageParams + { + Content = text, + AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, + IsTTS = isTTS, + Embeds = embeds.Select(x => x.ToModel()).ToArray(), + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified + }; + + if (ephemeral) + args.Flags = MessageFlags.Ephemeral; + + return await InteractionHelper.SendFollowupAsync(Discord, args, Token, Channel, options); + } + + /// + /// Sends a followup message for this interaction. + /// + /// The text of the message to be sent. + /// The file to upload. + /// The file name of the attachment. + /// A array of embeds to send with this response. Max 10. + /// if the message should be read out by a text-to-speech reader, otherwise . + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . + /// The allowed mentions for this response. + /// The request options for this response. + /// A to be sent with this response. + /// A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + /// + /// The sent message. + /// + public override async Task FollowupWithFileAsync( + Stream fileStream, + string fileName, + string text = null, + Embed[] embeds = null, + bool isTTS = false, + bool ephemeral = false, + AllowedMentions allowedMentions = null, + RequestOptions options = null, + MessageComponent component = null, + Embed embed = null) + { + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + Preconditions.NotNull(fileStream, nameof(fileStream), "File Stream must have data"); + Preconditions.NotNullOrEmpty(fileName, nameof(fileName), "File Name must not be empty or null"); + + var args = new API.Rest.CreateWebhookMessageParams + { + Content = text, + AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, + IsTTS = isTTS, + Embeds = embeds.Select(x => x.ToModel()).ToArray(), + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified, + File = fileStream is not null ? new MultipartFile(fileStream, fileName) : Optional.Unspecified + }; + + if (ephemeral) + args.Flags = MessageFlags.Ephemeral; + + return await InteractionHelper.SendFollowupAsync(Discord, args, Token, Channel, options); + } + + /// + /// Sends a followup message for this interaction. + /// + /// The text of the message to be sent. + /// The file to upload. + /// The file name of the attachment. + /// A array of embeds to send with this response. Max 10. + /// if the message should be read out by a text-to-speech reader, otherwise . + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . + /// The allowed mentions for this response. + /// The request options for this response. + /// A to be sent with this response. + /// A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + /// + /// The sent message. + /// + public override async Task FollowupWithFileAsync( + string filePath, + string text = null, + string fileName = null, + Embed[] embeds = null, + bool isTTS = false, + bool ephemeral = false, + AllowedMentions allowedMentions = null, + RequestOptions options = null, + MessageComponent component = null, + Embed embed = null) + { + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + Preconditions.NotNullOrEmpty(filePath, nameof(filePath), "Path must exist"); + + fileName ??= Path.GetFileName(filePath); + Preconditions.NotNullOrEmpty(fileName, nameof(fileName), "File Name must not be empty or null"); + + var args = new API.Rest.CreateWebhookMessageParams + { + Content = text, + AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, + IsTTS = isTTS, + Embeds = embeds.Select(x => x.ToModel()).ToArray(), + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified, + File = !string.IsNullOrEmpty(filePath) ? new MultipartFile(new MemoryStream(File.ReadAllBytes(filePath), false), fileName) : Optional.Unspecified + }; + + if (ephemeral) + args.Flags = MessageFlags.Ephemeral; + + return await InteractionHelper.SendFollowupAsync(Discord, args, Token, Channel, options); + } + + /// + /// Acknowledges this interaction with the . + /// + /// + /// A string that contains json to write back to the incoming http request. + /// + public override string Defer(bool ephemeral = false, RequestOptions options = null) + { + if (!InteractionHelper.CanSendResponse(this)) + throw new TimeoutException($"Cannot defer an interaction after {InteractionHelper.ResponseTimeLimit} seconds!"); + + var response = new API.InteractionResponse + { + Type = InteractionResponseType.DeferredChannelMessageWithSource, + Data = new API.InteractionCallbackData + { + Flags = ephemeral ? MessageFlags.Ephemeral : Optional.Unspecified + } + }; + + lock (_lock) + { + if (_hasResponded) + { + throw new InvalidOperationException("Cannot respond or defer twice to the same interaction"); + } + } + + lock (_lock) + { + _hasResponded = true; + } + + return SerializePayload(response); + } + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestCommandBaseData.cs b/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestCommandBaseData.cs new file mode 100644 index 000000000..4227c802a --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestCommandBaseData.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Model = Discord.API.ApplicationCommandInteractionData; + +namespace Discord.Rest +{ + /// + /// Represents the base data tied with the interaction. + /// + public class RestCommandBaseData : RestEntity, IApplicationCommandInteractionData where TOption : IApplicationCommandInteractionDataOption + { + /// + public string Name { get; private set; } + + /// + /// Gets a collection of received with this interaction. + /// + public virtual IReadOnlyCollection Options { get; internal set; } + + internal RestResolvableData ResolvableData; + + internal RestCommandBaseData(BaseDiscordClient client, Model model) + : base(client, model.Id) + { + } + + internal static async Task CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel) + { + var entity = new RestCommandBaseData(client, model); + await entity.UpdateAsync(client, model, guild, channel).ConfigureAwait(false); + return entity; + } + + internal virtual async Task UpdateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel) + { + Name = model.Name; + if (model.Resolved.IsSpecified && ResolvableData == null) + { + ResolvableData = new RestResolvableData(); + await ResolvableData.PopulateAsync(client, guild, channel, model).ConfigureAwait(false); + } + } + + IReadOnlyCollection IApplicationCommandInteractionData.Options + => (IReadOnlyCollection)Options; + } + + /// + /// Represents the base data tied with the interaction. + /// + public class RestCommandBaseData : RestCommandBaseData + { + internal RestCommandBaseData(DiscordRestClient client, Model model) + : base(client, model) { } + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestResolvableData.cs b/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestResolvableData.cs new file mode 100644 index 000000000..710207ef9 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/CommandBase/RestResolvableData.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.Rest +{ + internal class RestResolvableData where T : API.IResolvable + { + internal readonly Dictionary GuildMembers + = new Dictionary(); + internal readonly Dictionary Users + = new Dictionary(); + internal readonly Dictionary Channels + = new Dictionary(); + internal readonly Dictionary Roles + = new Dictionary(); + internal readonly Dictionary Messages + = new Dictionary(); + + internal async Task PopulateAsync(DiscordRestClient discord, RestGuild guild, IRestMessageChannel channel, T model) + { + var resolved = model.Resolved.Value; + + if (resolved.Users.IsSpecified) + { + foreach (var user in resolved.Users.Value) + { + var restUser = RestUser.Create(discord, user.Value); + + Users.Add(ulong.Parse(user.Key), restUser); + } + } + + if (resolved.Channels.IsSpecified) + { + var channels = await guild.GetChannelsAsync().ConfigureAwait(false); + + foreach (var channelModel in resolved.Channels.Value) + { + var restChannel = channels.FirstOrDefault(x => x.Id == channelModel.Value.Id); + + restChannel.Update(channelModel.Value); + + Channels.Add(ulong.Parse(channelModel.Key), restChannel); + } + } + + if (resolved.Members.IsSpecified) + { + foreach (var member in resolved.Members.Value) + { + // pull the adjacent user model + member.Value.User = resolved.Users.Value.FirstOrDefault(x => x.Key == member.Key).Value; + var restMember = RestGuildUser.Create(discord, guild, member.Value); + + GuildMembers.Add(ulong.Parse(member.Key), restMember); + } + } + + if (resolved.Roles.IsSpecified) + { + foreach (var role in resolved.Roles.Value) + { + var restRole = RestRole.Create(discord, guild, role.Value); + + Roles.Add(ulong.Parse(role.Key), restRole); + } + } + + if (resolved.Messages.IsSpecified) + { + foreach (var msg in resolved.Messages.Value) + { + channel ??= (IRestMessageChannel)(Channels.FirstOrDefault(x => x.Key == msg.Value.ChannelId).Value ?? await discord.GetChannelAsync(msg.Value.ChannelId).ConfigureAwait(false)); + + RestUser author; + + if (msg.Value.Author.IsSpecified) + { + author = RestUser.Create(discord, msg.Value.Author.Value); + } + else + { + author = RestGuildUser.Create(discord, guild, msg.Value.Member.Value); + } + + var message = RestMessage.Create(discord, channel, author, msg.Value); + + Messages.Add(message.Id, message); + } + } + } + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/MessageCommands/RestMessageCommand.cs b/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/MessageCommands/RestMessageCommand.cs new file mode 100644 index 000000000..53055cac3 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/MessageCommands/RestMessageCommand.cs @@ -0,0 +1,45 @@ +using System.Threading.Tasks; +using DataModel = Discord.API.ApplicationCommandInteractionData; +using Model = Discord.API.Interaction; + +namespace Discord.Rest +{ + /// + /// Represents a REST-based message command interaction. + /// + public class RestMessageCommand : RestCommandBase, IMessageCommandInteraction, IDiscordInteraction + { + /// + /// The data associated with this interaction. + /// + public new RestMessageCommandData Data { get; private set; } + + internal RestMessageCommand(DiscordRestClient client, Model model) + : base(client, model) + { + + } + + internal new static async Task CreateAsync(DiscordRestClient client, Model model) + { + var entity = new RestMessageCommand(client, model); + await entity.UpdateAsync(client, model).ConfigureAwait(false); + return entity; + } + + internal override async Task UpdateAsync(DiscordRestClient client, Model model) + { + await base.UpdateAsync(client, model).ConfigureAwait(false); + + var dataModel = model.Data.IsSpecified + ? (DataModel)model.Data.Value + : null; + + Data = await RestMessageCommandData.CreateAsync(client, dataModel, Guild, Channel).ConfigureAwait(false); + } + + //IMessageCommandInteraction + /// + IMessageCommandInteractionData IMessageCommandInteraction.Data => Data; + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/MessageCommands/RestMessageCommandData.cs b/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/MessageCommands/RestMessageCommandData.cs new file mode 100644 index 000000000..8eadab617 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/MessageCommands/RestMessageCommandData.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Model = Discord.API.ApplicationCommandInteractionData; + +namespace Discord.Rest +{ + /// + /// Represents the data for a . + /// + public class RestMessageCommandData : RestCommandBaseData, IMessageCommandInteractionData, IDiscordInteractionData + { + /// + /// Gets the message associated with this message command. + /// + public RestMessage Message + => ResolvableData?.Messages.FirstOrDefault().Value; + + /// + /// + /// Note Not implemented for + /// + public override IReadOnlyCollection Options + => throw new System.NotImplementedException(); + + internal RestMessageCommandData(DiscordRestClient client, Model model) + : base(client, model) { } + + internal new static async Task CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel) + { + var entity = new RestMessageCommandData(client, model); + await entity.UpdateAsync(client, model, guild, channel).ConfigureAwait(false); + return entity; + } + + //IMessageCommandInteractionData + /// + IMessage IMessageCommandInteractionData.Message => Message; + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/UserCommands/RestUserCommand.cs b/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/UserCommands/RestUserCommand.cs new file mode 100644 index 000000000..58f1ed375 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/UserCommands/RestUserCommand.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DataModel = Discord.API.ApplicationCommandInteractionData; +using Model = Discord.API.Interaction; + +namespace Discord.Rest +{ + /// + /// Represents a REST-based user command. + /// + public class RestUserCommand : RestCommandBase, IUserCommandInteraction, IDiscordInteraction + { + /// + /// Gets the data associated with this interaction. + /// + public new RestUserCommandData Data { get; private set; } + + internal RestUserCommand(DiscordRestClient client, Model model) + : base(client, model) + { + } + + internal new static async Task CreateAsync(DiscordRestClient client, Model model) + { + var entity = new RestUserCommand(client, model); + await entity.UpdateAsync(client, model).ConfigureAwait(false); + return entity; + } + + internal override async Task UpdateAsync(DiscordRestClient client, Model model) + { + await base.UpdateAsync(client, model).ConfigureAwait(false); + + var dataModel = model.Data.IsSpecified + ? (DataModel)model.Data.Value + : null; + + Data = await RestUserCommandData.CreateAsync(client, dataModel, Guild, Channel).ConfigureAwait(false); + } + + //IUserCommandInteractionData + /// + IUserCommandInteractionData IUserCommandInteraction.Data => Data; + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/UserCommands/RestUserCommandData.cs b/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/UserCommands/RestUserCommandData.cs new file mode 100644 index 000000000..7563eecc7 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/ContextMenuCommands/UserCommands/RestUserCommandData.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Model = Discord.API.ApplicationCommandInteractionData; + +namespace Discord.Rest +{ + /// + /// Represents the data for a . + /// + public class RestUserCommandData : RestCommandBaseData, IUserCommandInteractionData, IDiscordInteractionData + { + /// + /// Gets the user who this command targets. + /// + public RestUser Member + => (RestUser)ResolvableData.GuildMembers.Values.FirstOrDefault() ?? ResolvableData.Users.Values.FirstOrDefault(); + + /// + /// + /// Note Not implemented for + /// + public override IReadOnlyCollection Options + => throw new System.NotImplementedException(); + + internal RestUserCommandData(DiscordRestClient client, Model model) + : base(client, model) { } + + internal new static async Task CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel) + { + var entity = new RestUserCommandData(client, model); + await entity.UpdateAsync(client, model, guild, channel).ConfigureAwait(false); + return entity; + } + + //IUserCommandInteractionData + /// + IUser IUserCommandInteractionData.User => Member; + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs b/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs new file mode 100644 index 000000000..7cfc6a2ec --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs @@ -0,0 +1,542 @@ +using Discord.API; +using Discord.API.Rest; +using Discord.Net; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; + +namespace Discord.Rest +{ + internal static class InteractionHelper + { + public const double ResponseTimeLimit = 3; + public const double ResponseAndFollowupLimit = 15; + + #region InteractionHelper + public static bool CanSendResponse(IDiscordInteraction interaction) + { + return (DateTime.UtcNow - interaction.CreatedAt).TotalSeconds < ResponseTimeLimit; + } + public static bool CanRespondOrFollowup(IDiscordInteraction interaction) + { + return (DateTime.UtcNow - interaction.CreatedAt).TotalMinutes <= ResponseAndFollowupLimit; + } + + public static Task DeleteAllGuildCommandsAsync(BaseDiscordClient client, ulong guildId, RequestOptions options = null) + { + return client.ApiClient.BulkOverwriteGuildApplicationCommandsAsync(guildId, Array.Empty(), options); + } + + public static Task DeleteAllGlobalCommandsAsync(BaseDiscordClient client, RequestOptions options = null) + { + return client.ApiClient.BulkOverwriteGlobalApplicationCommandsAsync(Array.Empty(), options); + } + + public static Task SendInteractionResponseAsync(BaseDiscordClient client, InteractionResponse response, + ulong interactionId, string interactionToken, RequestOptions options = null) + { + return client.ApiClient.CreateInteractionResponseAsync(response, interactionId, interactionToken, options); + } + + public static async Task GetOriginalResponseAsync(BaseDiscordClient client, IMessageChannel channel, + IDiscordInteraction interaction, RequestOptions options = null) + { + var model = await client.ApiClient.GetInteractionResponseAsync(interaction.Token, options).ConfigureAwait(false); + return RestInteractionMessage.Create(client, model, interaction.Token, channel); + } + + public static async Task SendFollowupAsync(BaseDiscordClient client, CreateWebhookMessageParams args, + string token, IMessageChannel channel, RequestOptions options = null) + { + var model = await client.ApiClient.CreateInteractionFollowupMessageAsync(args, token, options).ConfigureAwait(false); + + var entity = RestFollowupMessage.Create(client, model, token, channel); + return entity; + } + #endregion + + #region Global commands + public static async Task GetGlobalCommandAsync(BaseDiscordClient client, ulong id, + RequestOptions options = null) + { + var model = await client.ApiClient.GetGlobalApplicationCommandAsync(id, options).ConfigureAwait(false); + + return RestGlobalCommand.Create(client, model); + } + public static Task CreateGlobalCommandAsync(BaseDiscordClient client, + Action func, RequestOptions options = null) where TArg : ApplicationCommandProperties + { + var args = Activator.CreateInstance(typeof(TArg)); + func((TArg)args); + return CreateGlobalCommandAsync(client, (TArg)args, options); + } + public static async Task CreateGlobalCommandAsync(BaseDiscordClient client, + ApplicationCommandProperties arg, RequestOptions options = null) + { + Preconditions.NotNullOrEmpty(arg.Name, nameof(arg.Name)); + + var model = new CreateApplicationCommandParams + { + Name = arg.Name.Value, + Type = arg.Type, + DefaultPermission = arg.IsDefaultPermission.IsSpecified + ? arg.IsDefaultPermission.Value + : Optional.Unspecified + }; + + if (arg is SlashCommandProperties slashProps) + { + Preconditions.NotNullOrEmpty(slashProps.Description, nameof(slashProps.Description)); + + model.Description = slashProps.Description.Value; + + model.Options = slashProps.Options.IsSpecified + ? slashProps.Options.Value.Select(x => new ApplicationCommandOption(x)).ToArray() + : Optional.Unspecified; + } + + return await client.ApiClient.CreateGlobalApplicationCommandAsync(model, options).ConfigureAwait(false); + } + + public static async Task BulkOverwriteGlobalCommandsAsync(BaseDiscordClient client, + ApplicationCommandProperties[] args, RequestOptions options = null) + { + Preconditions.NotNull(args, nameof(args)); + + var models = new List(); + + foreach (var arg in args) + { + Preconditions.NotNullOrEmpty(arg.Name, nameof(arg.Name)); + + var model = new CreateApplicationCommandParams + { + Name = arg.Name.Value, + Type = arg.Type, + DefaultPermission = arg.IsDefaultPermission.IsSpecified + ? arg.IsDefaultPermission.Value + : Optional.Unspecified + }; + + if (arg is SlashCommandProperties slashProps) + { + Preconditions.NotNullOrEmpty(slashProps.Description, nameof(slashProps.Description)); + + model.Description = slashProps.Description.Value; + + model.Options = slashProps.Options.IsSpecified + ? slashProps.Options.Value.Select(x => new ApplicationCommandOption(x)).ToArray() + : Optional.Unspecified; + } + + models.Add(model); + } + + return await client.ApiClient.BulkOverwriteGlobalApplicationCommandsAsync(models.ToArray(), options).ConfigureAwait(false); + } + + public static async Task> BulkOverwriteGuildCommandsAsync(BaseDiscordClient client, ulong guildId, + ApplicationCommandProperties[] args, RequestOptions options = null) + { + Preconditions.NotNull(args, nameof(args)); + + var models = new List(); + + foreach (var arg in args) + { + Preconditions.NotNullOrEmpty(arg.Name, nameof(arg.Name)); + + var model = new CreateApplicationCommandParams + { + Name = arg.Name.Value, + Type = arg.Type, + DefaultPermission = arg.IsDefaultPermission.IsSpecified + ? arg.IsDefaultPermission.Value + : Optional.Unspecified + }; + + if (arg is SlashCommandProperties slashProps) + { + Preconditions.NotNullOrEmpty(slashProps.Description, nameof(slashProps.Description)); + + model.Description = slashProps.Description.Value; + + model.Options = slashProps.Options.IsSpecified + ? slashProps.Options.Value.Select(x => new ApplicationCommandOption(x)).ToArray() + : Optional.Unspecified; + } + + models.Add(model); + } + + return await client.ApiClient.BulkOverwriteGuildApplicationCommandsAsync(guildId, models.ToArray(), options).ConfigureAwait(false); + } + + private static TArg GetApplicationCommandProperties(IApplicationCommand command) + where TArg : ApplicationCommandProperties + { + bool isBaseClass = typeof(TArg) == typeof(ApplicationCommandProperties); + + switch (true) + { + case true when (typeof(TArg) == typeof(SlashCommandProperties) || isBaseClass) && command.Type == ApplicationCommandType.Slash: + return new SlashCommandProperties() as TArg; + case true when (typeof(TArg) == typeof(MessageCommandProperties) || isBaseClass) && command.Type == ApplicationCommandType.Message: + return new MessageCommandProperties() as TArg; + case true when (typeof(TArg) == typeof(UserCommandProperties) || isBaseClass) && command.Type == ApplicationCommandType.User: + return new UserCommandProperties() as TArg; + default: + throw new InvalidOperationException($"Cannot modify application command of type {command.Type} with the parameter type {typeof(TArg).FullName}"); + } + } + + public static Task ModifyGlobalCommandAsync(BaseDiscordClient client, IApplicationCommand command, + Action func, RequestOptions options = null) where TArg : ApplicationCommandProperties + { + var arg = GetApplicationCommandProperties(command); + func(arg); + return ModifyGlobalCommandAsync(client, command, arg, options); + } + + public static async Task ModifyGlobalCommandAsync(BaseDiscordClient client, IApplicationCommand command, + ApplicationCommandProperties args, RequestOptions options = null) + { + if (args.Name.IsSpecified) + { + Preconditions.AtMost(args.Name.Value.Length, 32, nameof(args.Name)); + Preconditions.AtLeast(args.Name.Value.Length, 1, nameof(args.Name)); + } + + var model = new ModifyApplicationCommandParams + { + Name = args.Name, + DefaultPermission = args.IsDefaultPermission.IsSpecified + ? args.IsDefaultPermission.Value + : Optional.Unspecified + }; + + if (args is SlashCommandProperties slashProps) + { + if (slashProps.Description.IsSpecified) + { + Preconditions.AtMost(slashProps.Description.Value.Length, 100, nameof(slashProps.Description)); + Preconditions.AtLeast(slashProps.Description.Value.Length, 1, nameof(slashProps.Description)); + } + + if (slashProps.Options.IsSpecified) + { + if (slashProps.Options.Value.Count > 10) + throw new ArgumentException("Option count must be 10 or less"); + } + + model.Description = slashProps.Description; + + model.Options = slashProps.Options.IsSpecified + ? slashProps.Options.Value.Select(x => new ApplicationCommandOption(x)).ToArray() + : Optional.Unspecified; + } + + return await client.ApiClient.ModifyGlobalApplicationCommandAsync(model, command.Id, options).ConfigureAwait(false); + } + + public static async Task DeleteGlobalCommandAsync(BaseDiscordClient client, IApplicationCommand command, RequestOptions options = null) + { + Preconditions.NotNull(command, nameof(command)); + Preconditions.NotEqual(command.Id, 0, nameof(command.Id)); + + await client.ApiClient.DeleteGlobalApplicationCommandAsync(command.Id, options).ConfigureAwait(false); + } + #endregion + + #region Guild Commands + public static Task CreateGuildCommandAsync(BaseDiscordClient client, ulong guildId, + Action func, RequestOptions options) where TArg : ApplicationCommandProperties + { + var args = Activator.CreateInstance(typeof(TArg)); + func((TArg)args); + return CreateGuildCommandAsync(client, guildId, (TArg)args, options); + } + + public static async Task CreateGuildCommandAsync(BaseDiscordClient client, ulong guildId, + ApplicationCommandProperties arg, RequestOptions options = null) + { + var model = new CreateApplicationCommandParams + { + Name = arg.Name.Value, + Type = arg.Type, + DefaultPermission = arg.IsDefaultPermission.IsSpecified + ? arg.IsDefaultPermission.Value + : Optional.Unspecified + }; + + if (arg is SlashCommandProperties slashProps) + { + Preconditions.NotNullOrEmpty(slashProps.Description, nameof(slashProps.Description)); + + model.Description = slashProps.Description.Value; + + model.Options = slashProps.Options.IsSpecified + ? slashProps.Options.Value.Select(x => new ApplicationCommandOption(x)).ToArray() + : Optional.Unspecified; + } + + return await client.ApiClient.CreateGuildApplicationCommandAsync(model, guildId, options).ConfigureAwait(false); + } + + public static Task ModifyGuildCommandAsync(BaseDiscordClient client, IApplicationCommand command, ulong guildId, + Action func, RequestOptions options = null) where TArg : ApplicationCommandProperties + { + var arg = GetApplicationCommandProperties(command); + func(arg); + return ModifyGuildCommandAsync(client, command, guildId, arg, options); + } + + public static async Task ModifyGuildCommandAsync(BaseDiscordClient client, IApplicationCommand command, ulong guildId, + ApplicationCommandProperties arg, RequestOptions options = null) + { + var model = new ModifyApplicationCommandParams + { + Name = arg.Name, + DefaultPermission = arg.IsDefaultPermission.IsSpecified + ? arg.IsDefaultPermission.Value + : Optional.Unspecified + }; + + if (arg is SlashCommandProperties slashProps) + { + Preconditions.NotNullOrEmpty(slashProps.Description, nameof(slashProps.Description)); + + model.Description = slashProps.Description.Value; + + model.Options = slashProps.Options.IsSpecified + ? slashProps.Options.Value.Select(x => new ApplicationCommandOption(x)).ToArray() + : Optional.Unspecified; + } + + return await client.ApiClient.ModifyGuildApplicationCommandAsync(model, guildId, command.Id, options).ConfigureAwait(false); + } + + public static async Task DeleteGuildCommandAsync(BaseDiscordClient client, ulong guildId, IApplicationCommand command, RequestOptions options = null) + { + Preconditions.NotNull(command, nameof(command)); + Preconditions.NotEqual(command.Id, 0, nameof(command.Id)); + + await client.ApiClient.DeleteGuildApplicationCommandAsync(guildId, command.Id, options).ConfigureAwait(false); + } + + public static Task DeleteUnknownApplicationCommandAsync(BaseDiscordClient client, ulong? guildId, IApplicationCommand command, RequestOptions options = null) + { + return guildId.HasValue + ? DeleteGuildCommandAsync(client, guildId.Value, command, options) + : DeleteGlobalCommandAsync(client, command, options); + } + #endregion + + #region Responses + public static async Task ModifyFollowupMessageAsync(BaseDiscordClient client, RestFollowupMessage message, Action func, + RequestOptions options = null) + { + var args = new MessageProperties(); + func(args); + + var embed = args.Embed; + var embeds = args.Embeds; + + bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : !string.IsNullOrEmpty(message.Content); + bool hasEmbeds = embed.IsSpecified && embed.Value != null || embeds.IsSpecified && embeds.Value?.Length > 0 || message.Embeds.Any(); + bool hasComponents = args.Components.IsSpecified && args.Components.Value != null; + + if (!hasComponents && !hasText && !hasEmbeds) + Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); + + var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List() : null; + + if (embed.IsSpecified && embed.Value != null) + { + apiEmbeds.Add(embed.Value.ToModel()); + } + + if (embeds.IsSpecified && embeds.Value != null) + { + apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel())); + } + + Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); + + var apiArgs = new ModifyInteractionResponseParams + { + Content = args.Content, + Embeds = apiEmbeds?.ToArray() ?? Optional.Unspecified, + AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() : Optional.Unspecified, + Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional.Unspecified + }; + + return await client.ApiClient.ModifyInteractionFollowupMessageAsync(apiArgs, message.Id, message.Token, options).ConfigureAwait(false); + } + public static async Task DeleteFollowupMessageAsync(BaseDiscordClient client, RestFollowupMessage message, RequestOptions options = null) + => await client.ApiClient.DeleteInteractionFollowupMessageAsync(message.Id, message.Token, options); + public static async Task ModifyInteractionResponseAsync(BaseDiscordClient client, string token, Action func, + RequestOptions options = null) + { + var args = new MessageProperties(); + func(args); + + var embed = args.Embed; + var embeds = args.Embeds; + + bool hasText = !string.IsNullOrEmpty(args.Content.GetValueOrDefault()); + bool hasEmbeds = embed.IsSpecified && embed.Value != null || embeds.IsSpecified && embeds.Value?.Length > 0; + bool hasComponents = args.Components.IsSpecified && args.Components.Value != null; + + if (!hasComponents && !hasText && !hasEmbeds) + Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); + + var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List() : null; + + if (embed.IsSpecified && embed.Value != null) + { + apiEmbeds.Add(embed.Value.ToModel()); + } + + if (embeds.IsSpecified && embeds.Value != null) + { + apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel())); + } + + Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); + + var apiArgs = new ModifyInteractionResponseParams + { + Content = args.Content, + Embeds = apiEmbeds?.ToArray() ?? Optional.Unspecified, + AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value?.ToModel() : Optional.Unspecified, + Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional.Unspecified, + Flags = args.Flags + }; + + return await client.ApiClient.ModifyInteractionResponseAsync(apiArgs, token, options).ConfigureAwait(false); + } + + public static async Task DeleteInteractionResponseAsync(BaseDiscordClient client, RestInteractionMessage message, RequestOptions options = null) + => await client.ApiClient.DeleteInteractionFollowupMessageAsync(message.Id, message.Token, options); + + public static Task SendAutocompleteResultAsync(BaseDiscordClient client, IEnumerable result, ulong interactionId, + string interactionToken, RequestOptions options) + { + result ??= Array.Empty(); + + Preconditions.AtMost(result.Count(), 20, nameof(result), "A maximum of 20 choices are allowed!"); + + var apiArgs = new InteractionResponse + { + Type = InteractionResponseType.ApplicationCommandAutocompleteResult, + Data = new InteractionCallbackData + { + Choices = result.Any() + ? result.Select(x => new ApplicationCommandOptionChoice { Name = x.Name, Value = x.Value }).ToArray() + : Array.Empty() + } + }; + + return client.ApiClient.CreateInteractionResponseAsync(apiArgs, interactionId, interactionToken, options); + } + #endregion + + #region Guild permissions + public static async Task> GetGuildCommandPermissionsAsync(BaseDiscordClient client, + ulong guildId, RequestOptions options) + { + var models = await client.ApiClient.GetGuildApplicationCommandPermissionsAsync(guildId, options); + return models.Select(x => + new GuildApplicationCommandPermission(x.Id, x.ApplicationId, guildId, x.Permissions.Select( + y => new ApplicationCommandPermission(y.Id, y.Type, y.Permission)) + .ToArray()) + ).ToArray(); + } + + public static async Task GetGuildCommandPermissionAsync(BaseDiscordClient client, + ulong guildId, ulong commandId, RequestOptions options) + { + try + { + var model = await client.ApiClient.GetGuildApplicationCommandPermissionAsync(guildId, commandId, options); + return new GuildApplicationCommandPermission(model.Id, model.ApplicationId, guildId, model.Permissions.Select( + y => new ApplicationCommandPermission(y.Id, y.Type, y.Permission)).ToArray()); + } + catch (HttpException x) + { + if (x.HttpCode == HttpStatusCode.NotFound) + return null; + throw; + } + } + + public static async Task ModifyGuildCommandPermissionsAsync(BaseDiscordClient client, ulong guildId, ulong commandId, + ApplicationCommandPermission[] args, RequestOptions options) + { + Preconditions.NotNull(args, nameof(args)); + Preconditions.AtMost(args.Length, 10, nameof(args)); + Preconditions.AtLeast(args.Length, 0, nameof(args)); + + var permissionsList = new List(); + + foreach (var arg in args) + { + var permissions = new ApplicationCommandPermissions + { + Id = arg.TargetId, + Permission = arg.Permission, + Type = arg.TargetType + }; + + permissionsList.Add(permissions); + } + + var model = new ModifyGuildApplicationCommandPermissionsParams + { + Permissions = permissionsList.ToArray() + }; + + var apiModel = await client.ApiClient.ModifyApplicationCommandPermissionsAsync(model, guildId, commandId, options); + + return new GuildApplicationCommandPermission(apiModel.Id, apiModel.ApplicationId, guildId, apiModel.Permissions.Select( + x => new ApplicationCommandPermission(x.Id, x.Type, x.Permission)).ToArray()); + } + + public static async Task> BatchEditGuildCommandPermissionsAsync(BaseDiscordClient client, ulong guildId, + IDictionary args, RequestOptions options) + { + Preconditions.NotNull(args, nameof(args)); + Preconditions.NotEqual(args.Count, 0, nameof(args)); + + var models = new List(); + + foreach (var arg in args) + { + Preconditions.AtMost(arg.Value.Length, 10, nameof(args)); + + var model = new ModifyGuildApplicationCommandPermissions + { + Id = arg.Key, + Permissions = arg.Value.Select(x => new ApplicationCommandPermissions + { + Id = x.TargetId, + Permission = x.Permission, + Type = x.TargetType + }).ToArray() + }; + + models.Add(model); + } + + var apiModels = await client.ApiClient.BatchModifyApplicationCommandPermissionsAsync(models.ToArray(), guildId, options); + + return apiModels.Select( + x => new GuildApplicationCommandPermission(x.Id, x.ApplicationId, x.GuildId, x.Permissions.Select( + y => new ApplicationCommandPermission(y.Id, y.Type, y.Permission)).ToArray())).ToArray(); + } + #endregion + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/MessageComponents/RestMessageComponent.cs b/src/Discord.Net.Rest/Entities/Interactions/MessageComponents/RestMessageComponent.cs new file mode 100644 index 000000000..eb47e15aa --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/MessageComponents/RestMessageComponent.cs @@ -0,0 +1,452 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Model = Discord.API.Interaction; +using DataModel = Discord.API.MessageComponentInteractionData; +using System.IO; +using Discord.Net.Rest; + +namespace Discord.Rest +{ + /// + /// Represents a REST-based message component. + /// + internal class RestMessageComponent : RestInteraction, IComponentInteraction, IDiscordInteraction + { + /// + /// Gets the data received with this interaction, contains the button that was clicked. + /// + public new RestMessageComponentData Data { get; } + + /// + /// Gets the message that contained the trigger for this interaction. + /// + public RestUserMessage Message { get; private set; } + + private object _lock = new object(); + internal override bool _hasResponded { get; set; } = false; + + internal RestMessageComponent(BaseDiscordClient client, Model model) + : base(client, model.Id) + { + var dataModel = model.Data.IsSpecified + ? (DataModel)model.Data.Value + : null; + + Data = new RestMessageComponentData(dataModel); + } + + internal new static async Task CreateAsync(DiscordRestClient client, Model model) + { + var entity = new RestMessageComponent(client, model); + await entity.UpdateAsync(client, model).ConfigureAwait(false); + return entity; + } + internal override async Task UpdateAsync(DiscordRestClient discord, Model model) + { + await base.UpdateAsync(discord, model).ConfigureAwait(false); + + if (model.Message.IsSpecified && model.ChannelId.IsSpecified) + { + if (Message == null) + { + Message = RestUserMessage.Create(Discord, Channel, User, model.Message.Value); + } + } + } + /// + /// Responds to an Interaction with type . + /// + /// The text of the message to be sent. + /// A array of embeds to send with this response. Max 10. + /// if the message should be read out by a text-to-speech reader, otherwise . + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . + /// The allowed mentions for this response. + /// The request options for this response. + /// A to be sent with this response. + /// A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + /// + /// A string that contains json to write back to the incoming http request. + /// + public override string Respond( + string text = null, + Embed[] embeds = null, + bool isTTS = false, + bool ephemeral = false, + AllowedMentions allowedMentions = null, + RequestOptions options = null, + MessageComponent component = null, + Embed embed = null) + { + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + if (!InteractionHelper.CanSendResponse(this)) + throw new TimeoutException($"Cannot respond to an interaction after {InteractionHelper.ResponseTimeLimit} seconds!"); + + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + + // check that user flag and user Id list are exclusive, same with role flag and role Id list + if (allowedMentions != null && allowedMentions.AllowedTypes.HasValue) + { + if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Users) && + allowedMentions.UserIds != null && allowedMentions.UserIds.Count > 0) + { + throw new ArgumentException("The Users flag is mutually exclusive with the list of User Ids.", nameof(allowedMentions)); + } + + if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Roles) && + allowedMentions.RoleIds != null && allowedMentions.RoleIds.Count > 0) + { + throw new ArgumentException("The Roles flag is mutually exclusive with the list of Role Ids.", nameof(allowedMentions)); + } + } + + var response = new API.InteractionResponse + { + Type = InteractionResponseType.ChannelMessageWithSource, + Data = new API.InteractionCallbackData + { + Content = text ?? Optional.Unspecified, + AllowedMentions = allowedMentions?.ToModel(), + Embeds = embeds.Select(x => x.ToModel()).ToArray(), + TTS = isTTS, + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified + } + }; + + if (ephemeral) + response.Data.Value.Flags = MessageFlags.Ephemeral; + + lock (_lock) + { + if (_hasResponded) + { + throw new InvalidOperationException("Cannot respond, update, or defer twice to the same interaction"); + } + } + + lock (_lock) + { + _hasResponded = true; + } + + return SerializePayload(response); + } + + /// + /// Updates the message which this component resides in with the type + /// + /// A delegate containing the properties to modify the message with. + /// The request options for this request. + /// A string that contains json to write back to the incoming http request. + public string Update(Action func, RequestOptions options = null) + { + var args = new MessageProperties(); + func(args); + + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + if (!InteractionHelper.CanSendResponse(this)) + throw new TimeoutException($"Cannot respond to an interaction after {InteractionHelper.ResponseTimeLimit} seconds!"); + + if (args.AllowedMentions.IsSpecified) + { + var allowedMentions = args.AllowedMentions.Value; + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions), "A max of 100 user Ids are allowed."); + } + + var embed = args.Embed; + var embeds = args.Embeds; + + bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : !string.IsNullOrEmpty(Message.Content); + bool hasEmbeds = embed.IsSpecified && embed.Value != null || embeds.IsSpecified && embeds.Value?.Length > 0 || Message.Embeds.Any(); + + if (!hasText && !hasEmbeds) + Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); + + var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List() : null; + + if (embed.IsSpecified && embed.Value != null) + { + apiEmbeds.Add(embed.Value.ToModel()); + } + + if (embeds.IsSpecified && embeds.Value != null) + { + apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel())); + } + + Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); + + // check that user flag and user Id list are exclusive, same with role flag and role Id list + if (args.AllowedMentions.IsSpecified && args.AllowedMentions.Value != null && args.AllowedMentions.Value.AllowedTypes.HasValue) + { + var allowedMentions = args.AllowedMentions.Value; + if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Users) + && allowedMentions.UserIds != null && allowedMentions.UserIds.Count > 0) + { + throw new ArgumentException("The Users flag is mutually exclusive with the list of User Ids.", nameof(args.AllowedMentions)); + } + + if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Roles) + && allowedMentions.RoleIds != null && allowedMentions.RoleIds.Count > 0) + { + throw new ArgumentException("The Roles flag is mutually exclusive with the list of Role Ids.", nameof(args.AllowedMentions)); + } + } + + var response = new API.InteractionResponse + { + Type = InteractionResponseType.UpdateMessage, + Data = new API.InteractionCallbackData + { + Content = args.Content, + AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value?.ToModel() : Optional.Unspecified, + Embeds = apiEmbeds?.ToArray() ?? Optional.Unspecified, + Components = args.Components.IsSpecified + ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Array.Empty() + : Optional.Unspecified, + Flags = args.Flags.IsSpecified ? args.Flags.Value ?? Optional.Unspecified : Optional.Unspecified + } + }; + + lock (_lock) + { + if (_hasResponded) + { + throw new InvalidOperationException("Cannot respond, update, or defer twice to the same interaction"); + } + } + + lock (_lock) + { + _hasResponded = true; + } + + return SerializePayload(response); + } + + /// + /// Sends a followup message for this interaction. + /// + /// The text of the message to be sent. + /// A array of embeds to send with this response. Max 10. + /// if the message should be read out by a text-to-speech reader, otherwise . + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . + /// The allowed mentions for this response. + /// The request options for this response. + /// A to be sent with this response. + /// A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + /// + /// The sent message. + /// + public override async Task FollowupAsync( + string text = null, + Embed[] embeds = null, + bool isTTS = false, + bool ephemeral = false, + AllowedMentions allowedMentions = null, + RequestOptions options = null, + MessageComponent component = null, + Embed embed = null) + { + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + + var args = new API.Rest.CreateWebhookMessageParams + { + Content = text, + AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, + IsTTS = isTTS, + Embeds = embeds.Select(x => x.ToModel()).ToArray(), + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified + }; + + if (ephemeral) + args.Flags = MessageFlags.Ephemeral; + + return await InteractionHelper.SendFollowupAsync(Discord, args, Token, Message.Channel, options).ConfigureAwait(false); + } + + /// + public override async Task FollowupWithFileAsync( + Stream fileStream, + string fileName, + string text = null, + Embed[] embeds = null, + bool isTTS = false, + bool ephemeral = false, + AllowedMentions allowedMentions = null, + RequestOptions options = null, + MessageComponent component = null, + Embed embed = null) + { + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + Preconditions.NotNull(fileStream, nameof(fileStream), "File Stream must have data"); + Preconditions.NotNullOrWhitespace(fileName, nameof(fileName), "File Name must not be empty or null"); + + var args = new API.Rest.CreateWebhookMessageParams + { + Content = text, + AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, + IsTTS = isTTS, + Embeds = embeds.Select(x => x.ToModel()).ToArray(), + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified, + File = fileStream is not null ? new MultipartFile(fileStream, fileName) : Optional.Unspecified + }; + + if (ephemeral) + args.Flags = MessageFlags.Ephemeral; + + return await InteractionHelper.SendFollowupAsync(Discord, args, Token, Message.Channel, options).ConfigureAwait(false); + } + + /// + public override async Task FollowupWithFileAsync( + string filePath, + string text = null, + string fileName = null, + Embed[] embeds = null, + bool isTTS = false, + bool ephemeral = false, + AllowedMentions allowedMentions = null, + RequestOptions options = null, + MessageComponent component = null, + Embed embed = null) + { + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + Preconditions.NotNullOrWhitespace(filePath, nameof(filePath), "Path must exist"); + + var args = new API.Rest.CreateWebhookMessageParams + { + Content = text, + AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, + IsTTS = isTTS, + Embeds = embeds.Select(x => x.ToModel()).ToArray(), + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified, + File = !string.IsNullOrEmpty(filePath) ? new MultipartFile(new MemoryStream(File.ReadAllBytes(filePath), false), fileName) : Optional.Unspecified + }; + + if (ephemeral) + args.Flags = MessageFlags.Ephemeral; + + return await InteractionHelper.SendFollowupAsync(Discord, args, Token, Message.Channel, options).ConfigureAwait(false); + } + + /// + /// Defers an interaction and responds with type 5 () + /// + /// to send this message ephemerally, otherwise . + /// The request options for this request. + /// + /// A string that contains json to write back to the incoming http request. + /// + public string DeferLoading(bool ephemeral = false, RequestOptions options = null) + { + if (!InteractionHelper.CanSendResponse(this)) + throw new TimeoutException($"Cannot defer an interaction after {InteractionHelper.ResponseTimeLimit} seconds of no response/acknowledgement"); + + var response = new API.InteractionResponse + { + Type = InteractionResponseType.DeferredChannelMessageWithSource, + Data = ephemeral ? new API.InteractionCallbackData { Flags = MessageFlags.Ephemeral } : Optional.Unspecified + }; + + lock (_lock) + { + if (_hasResponded) + { + throw new InvalidOperationException("Cannot respond or defer twice to the same interaction"); + } + } + + lock (_lock) + { + _hasResponded = true; + } + + return SerializePayload(response); + } + + /// + /// + /// + /// + /// + /// + /// A string that contains json to write back to the incoming http request. + /// + /// + /// + public override string Defer(bool ephemeral = false, RequestOptions options = null) + { + if (!InteractionHelper.CanSendResponse(this)) + throw new TimeoutException($"Cannot defer an interaction after {InteractionHelper.ResponseTimeLimit} seconds of no response/acknowledgement"); + + var response = new API.InteractionResponse + { + Type = InteractionResponseType.DeferredUpdateMessage, + Data = ephemeral ? new API.InteractionCallbackData { Flags = MessageFlags.Ephemeral } : Optional.Unspecified + }; + + lock (_lock) + { + if (_hasResponded) + { + throw new InvalidOperationException("Cannot respond or defer twice to the same interaction"); + } + } + + lock (_lock) + { + _hasResponded = true; + } + + return SerializePayload(response); + } + + //IComponentInteraction + /// + IComponentInteractionData IComponentInteraction.Data => Data; + + /// + IUserMessage IComponentInteraction.Message => Message; + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/MessageComponents/RestMessageComponentData.cs b/src/Discord.Net.Rest/Entities/Interactions/MessageComponents/RestMessageComponentData.cs new file mode 100644 index 000000000..e865c208c --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/MessageComponents/RestMessageComponentData.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Model = Discord.API.MessageComponentInteractionData; + +namespace Discord.Rest +{ + /// + /// Represents data for a . + /// + public class RestMessageComponentData : IComponentInteractionData, IDiscordInteractionData + { + /// + /// Gets the components Custom Id that was clicked. + /// + public string CustomId { get; } + + /// + /// Gets the type of the component clicked. + /// + public ComponentType Type { get; } + + /// + /// Gets the value(s) of a interaction response. + /// + public IReadOnlyCollection Values { get; } + + internal RestMessageComponentData(Model model) + { + CustomId = model.CustomId; + Type = model.ComponentType; + Values = model.Values.GetValueOrDefault(); + } + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommand.cs b/src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommand.cs new file mode 100644 index 000000000..c3edaf6ff --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommand.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using Model = Discord.API.ApplicationCommand; + +namespace Discord.Rest +{ + /// + /// Represents a Rest-based implementation of the . + /// + public abstract class RestApplicationCommand : RestEntity, IApplicationCommand + { + /// + public ulong ApplicationId { get; private set; } + + /// + public ApplicationCommandType Type { get; private set; } + + /// + public string Name { get; private set; } + + /// + public string Description { get; private set; } + + /// + public bool IsDefaultPermission { get; private set; } + + /// + /// The options of this command. + /// + public IReadOnlyCollection Options { get; private set; } + + /// + public DateTimeOffset CreatedAt + => SnowflakeUtils.FromSnowflake(Id); + + internal RestApplicationCommand(BaseDiscordClient client, ulong id) + : base(client, id) { } + + internal static RestApplicationCommand Create(BaseDiscordClient client, Model model, ulong? guildId) + { + return guildId.HasValue + ? RestGuildCommand.Create(client, model, guildId.Value) + : RestGlobalCommand.Create(client, model); + } + + internal virtual void Update(Model model) + { + Type = model.Type; + ApplicationId = model.ApplicationId; + Name = model.Name; + Description = model.Description; + IsDefaultPermission = model.DefaultPermissions.GetValueOrDefault(true); + + Options = model.Options.IsSpecified + ? model.Options.Value.Select(RestApplicationCommandOption.Create).ToImmutableArray() + : ImmutableArray.Create(); + } + + /// + public abstract Task DeleteAsync(RequestOptions options = null); + + /// + public Task ModifyAsync(Action func, RequestOptions options = null) + { + return ModifyAsync(func, options); + } + + /// + public abstract Task ModifyAsync(Action func, RequestOptions options = null) + where TArg : ApplicationCommandProperties; + + IReadOnlyCollection IApplicationCommand.Options => Options; + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommandChoice.cs b/src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommandChoice.cs new file mode 100644 index 000000000..a40491a2c --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommandChoice.cs @@ -0,0 +1,22 @@ +using Model = Discord.API.ApplicationCommandOptionChoice; + +namespace Discord.Rest +{ + /// + /// Represents a Rest-based implementation of . + /// + public class RestApplicationCommandChoice : IApplicationCommandOptionChoice + { + /// + public string Name { get; } + + /// + public object Value { get; } + + internal RestApplicationCommandChoice(Model model) + { + Name = model.Name; + Value = model.Value; + } + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommandOption.cs b/src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommandOption.cs new file mode 100644 index 000000000..d5c261e0b --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommandOption.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Model = Discord.API.ApplicationCommandOption; + +namespace Discord.Rest +{ + /// + /// Represents a Rest-based implementation of . + /// + public class RestApplicationCommandOption : IApplicationCommandOption + { + #region RestApplicationCommandOption + /// + public ApplicationCommandOptionType Type { get; private set; } + + /// + public string Name { get; private set; } + + /// + public string Description { get; private set; } + + /// + public bool? IsDefault { get; private set; } + + /// + public bool? IsRequired { get; private set; } + + /// + public double? MinValue { get; private set; } + + /// + public double? MaxValue { get; private set; } + + /// + /// A collection of 's for this command. + /// + public IReadOnlyCollection Choices { get; private set; } + + /// + /// A collection of 's for this command. + /// + public IReadOnlyCollection Options { get; private set; } + + /// + /// The allowed channel types for this option. + /// + public IReadOnlyCollection ChannelTypes { get; private set; } + + internal RestApplicationCommandOption() { } + + internal static RestApplicationCommandOption Create(Model model) + { + var options = new RestApplicationCommandOption(); + options.Update(model); + return options; + } + + internal void Update(Model model) + { + Type = model.Type; + Name = model.Name; + Description = model.Description; + + if (model.Default.IsSpecified) + IsDefault = model.Default.Value; + + if (model.Required.IsSpecified) + IsRequired = model.Required.Value; + + if (model.MinValue.IsSpecified) + MinValue = model.MinValue.Value; + + if (model.MaxValue.IsSpecified) + MaxValue = model.MaxValue.Value; + + Options = model.Options.IsSpecified + ? model.Options.Value.Select(Create).ToImmutableArray() + : ImmutableArray.Create(); + + Choices = model.Choices.IsSpecified + ? model.Choices.Value.Select(x => new RestApplicationCommandChoice(x)).ToImmutableArray() + : ImmutableArray.Create(); + + ChannelTypes = model.ChannelTypes.IsSpecified + ? model.ChannelTypes.Value.ToImmutableArray() + : ImmutableArray.Create(); + } + #endregion + + #region IApplicationCommandOption + IReadOnlyCollection IApplicationCommandOption.Options + => Options; + IReadOnlyCollection IApplicationCommandOption.Choices + => Choices; + #endregion + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/RestGlobalCommand.cs b/src/Discord.Net.Rest/Entities/Interactions/RestGlobalCommand.cs new file mode 100644 index 000000000..c319bcf34 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/RestGlobalCommand.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading.Tasks; +using Model = Discord.API.ApplicationCommand; + +namespace Discord.Rest +{ + /// + /// Represents a Rest-based global application command. + /// + public class RestGlobalCommand : RestApplicationCommand + { + internal RestGlobalCommand(BaseDiscordClient client, ulong id) + : base(client, id) { } + + internal static RestGlobalCommand Create(BaseDiscordClient client, Model model) + { + var entity = new RestGlobalCommand(client, model.Id); + entity.Update(model); + return entity; + } + + /// + public override async Task DeleteAsync(RequestOptions options = null) + => await InteractionHelper.DeleteGlobalCommandAsync(Discord, this).ConfigureAwait(false); + + /// + /// Modifies this . + /// + /// The delegate containing the properties to modify the command with. + /// The options to be used when sending the request. + /// + /// The modified command. + /// + public override async Task ModifyAsync(Action func, RequestOptions options = null) + { + var cmd = await InteractionHelper.ModifyGlobalCommandAsync(Discord, this, func, options).ConfigureAwait(false); + Update(cmd); + } + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/RestGuildCommand.cs b/src/Discord.Net.Rest/Entities/Interactions/RestGuildCommand.cs new file mode 100644 index 000000000..00804e57e --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/RestGuildCommand.cs @@ -0,0 +1,83 @@ +using System; +using System.Threading.Tasks; +using Model = Discord.API.ApplicationCommand; + +namespace Discord.Rest +{ + /// + /// Represents a Rest-based guild application command. + /// + public class RestGuildCommand : RestApplicationCommand + { + /// + /// The guild Id where this command originates. + /// + public ulong GuildId { get; private set; } + + internal RestGuildCommand(BaseDiscordClient client, ulong id, ulong guildId) + : base(client, id) + { + GuildId = guildId; + } + + internal static RestGuildCommand Create(BaseDiscordClient client, Model model, ulong guildId) + { + var entity = new RestGuildCommand(client, model.Id, guildId); + entity.Update(model); + return entity; + } + + /// + public override async Task DeleteAsync(RequestOptions options = null) + => await InteractionHelper.DeleteGuildCommandAsync(Discord, GuildId, this).ConfigureAwait(false); + + /// + /// Modifies this . + /// + /// The delegate containing the properties to modify the command with. + /// The options to be used when sending the request. + /// + /// The modified command + /// + public override async Task ModifyAsync(Action func, RequestOptions options = null) + { + var model = await InteractionHelper.ModifyGuildCommandAsync(Discord, this, GuildId, func, options).ConfigureAwait(false); + Update(model); + } + + /// + /// Gets this commands permissions inside of the current guild. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a + /// object defining the permissions of the current slash command. + /// + public Task GetCommandPermission(RequestOptions options = null) + => InteractionHelper.GetGuildCommandPermissionAsync(Discord, GuildId, Id, options); + + /// + /// Modifies the current command permissions for this guild command. + /// + /// The permissions to overwrite. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous modification operation. The task result contains a + /// object containing the modified permissions. + /// + public Task ModifyCommandPermissions(ApplicationCommandPermission[] permissions, RequestOptions options = null) + => InteractionHelper.ModifyGuildCommandPermissionsAsync(Discord, GuildId, Id, permissions, options); + + /// + /// Gets the guild that this slash command resides in. + /// + /// if you want the approximate member and presence counts for the guild, otherwise . + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a + /// . + /// + public Task GetGuild(bool withCounts = false, RequestOptions options = null) + => ClientHelper.GetGuildAsync(Discord, GuildId, withCounts, options); + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/RestInteraction.cs b/src/Discord.Net.Rest/Entities/Interactions/RestInteraction.cs new file mode 100644 index 000000000..103c43ffb --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/RestInteraction.cs @@ -0,0 +1,224 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Model = Discord.API.Interaction; +using DataModel = Discord.API.ApplicationCommandInteractionData; +using Newtonsoft.Json; + +namespace Discord.Rest +{ + /// + /// Represents a REST-based interaction. + /// + public abstract class RestInteraction : RestEntity, IDiscordInteraction + { + /// + public InteractionType Type { get; private set; } + + /// + public IDiscordInteractionData Data { get; private set; } + + /// + public string Token { get; private set; } + + /// + public int Version { get; private set; } + + /// + /// Gets the user who invoked the interaction. + /// + public RestUser User { get; private set; } + + /// + public DateTimeOffset CreatedAt { get; private set; } + + internal abstract bool _hasResponded { get; set; } + + /// + /// if the token is valid for replying to, otherwise . + /// + public bool IsValidToken + => InteractionHelper.CanRespondOrFollowup(this); + + /// + /// Gets the channel that this interaction was executed in. + /// + public IRestMessageChannel Channel { get; private set; } + + /// + /// Gets the guild this interaction was executed in. + /// + public RestGuild Guild { get; private set; } + + internal RestInteraction(BaseDiscordClient discord, ulong id) + : base(discord, id) + { + CreatedAt = discord.UseInteractionSnowflakeDate + ? SnowflakeUtils.FromSnowflake(Id) + : DateTime.UtcNow; + } + + internal static async Task CreateAsync(DiscordRestClient client, Model model) + { + if(model.Type == InteractionType.Ping) + { + return await RestPingInteraction.CreateAsync(client, model); + } + + if (model.Type == InteractionType.ApplicationCommand) + { + var dataModel = model.Data.IsSpecified + ? (DataModel)model.Data.Value + : null; + + if (dataModel == null) + return null; + + return dataModel.Type switch + { + ApplicationCommandType.Slash => await RestSlashCommand.CreateAsync(client, model).ConfigureAwait(false), + ApplicationCommandType.Message => await RestMessageCommand.CreateAsync(client, model).ConfigureAwait(false), + ApplicationCommandType.User => await RestUserCommand.CreateAsync(client, model).ConfigureAwait(false), + _ => null + }; + } + + if (model.Type == InteractionType.MessageComponent) + return await RestMessageComponent.CreateAsync(client, model).ConfigureAwait(false); + + if (model.Type == InteractionType.ApplicationCommandAutocomplete) + return await RestAutocompleteInteraction.CreateAsync(client, model).ConfigureAwait(false); + + return null; + } + + internal virtual async Task UpdateAsync(DiscordRestClient discord, Model model) + { + Data = model.Data.IsSpecified + ? model.Data.Value + : null; + Token = model.Token; + Version = model.Version; + Type = model.Type; + + if(Guild == null && model.GuildId.IsSpecified) + { + Guild = await discord.GetGuildAsync(model.GuildId.Value); + } + + if (User == null) + { + if (model.Member.IsSpecified && model.GuildId.IsSpecified) + { + User = RestGuildUser.Create(Discord, Guild, model.Member.Value); + } + else + { + User = RestUser.Create(Discord, model.User.Value); + } + } + + if(Channel == null && model.ChannelId.IsSpecified) + { + Channel = (IRestMessageChannel)await discord.GetChannelAsync(model.ChannelId.Value); + } + } + + internal string SerializePayload(object payload) + { + var json = new StringBuilder(); + using (var text = new StringWriter(json)) + using (var writer = new JsonTextWriter(text)) + DiscordRestClient.Serializer.Serialize(writer, payload); + + return json.ToString(); + } + + /// + public abstract string Defer(bool ephemeral = false, RequestOptions options = null); + /// + public abstract Task FollowupAsync(string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null); + /// + /// Gets the original response for this interaction. + /// + /// The request options for this request. + /// A that represents the initial response. + public Task GetOriginalResponseAsync(RequestOptions options = null) + => InteractionHelper.GetOriginalResponseAsync(Discord, Channel, this, options); + + /// + /// Edits original response for this interaction. + /// + /// A delegate containing the properties to modify the message with. + /// The request options for this request. + /// A that represents the initial response. + public async Task ModifyOriginalResponseAsync(Action func, RequestOptions options = null) + { + var model = await InteractionHelper.ModifyInteractionResponseAsync(Discord, Token, func, options); + return RestInteractionMessage.Create(Discord, model, Token, Channel); + } + /// + public abstract string Respond(string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null); + /// + /// Sends a followup message for this interaction. + /// + /// The text of the message to be sent. + /// The file to upload. + /// The file name of the attachment. + /// A array of embeds to send with this response. Max 10. + /// if the message should be read out by a text-to-speech reader, otherwise . + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . + /// The allowed mentions for this response. + /// The request options for this response. + /// A to be sent with this response. + /// A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + /// + /// The sent message. + /// + public abstract Task FollowupWithFileAsync(Stream fileStream, string fileName, string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, + AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null); + /// + /// Sends a followup message for this interaction. + /// + /// The text of the message to be sent. + /// The file to upload. + /// The file name of the attachment. + /// A array of embeds to send with this response. Max 10. + /// if the message should be read out by a text-to-speech reader, otherwise . + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . + /// The allowed mentions for this response. + /// The request options for this response. + /// A to be sent with this response. + /// A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + /// + /// The sent message. + /// + public abstract Task FollowupWithFileAsync(string filePath, string text = null, string fileName = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, + AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null); + + #region IDiscordInteraction + /// + Task IDiscordInteraction.RespondAsync(string text, Embed[] embeds, bool isTTS, bool ephemeral, AllowedMentions allowedMentions, RequestOptions options, MessageComponent component, Embed embed) + => Task.FromResult(Respond(text, embeds, isTTS, ephemeral, allowedMentions, options, component, embed)); + + Task IDiscordInteraction.DeferAsync(bool ephemeral, RequestOptions options) + => Task.FromResult(Defer(ephemeral, options)); + + /// + async Task IDiscordInteraction.FollowupAsync(string text, Embed[] embeds, bool isTTS, bool ephemeral, AllowedMentions allowedMentions, + RequestOptions options, MessageComponent component, Embed embed) + => await FollowupAsync(text, embeds, isTTS, ephemeral, allowedMentions, options, component, embed).ConfigureAwait(false); + + /// + async Task IDiscordInteraction.GetOriginalResponseAsync(RequestOptions options) + => await GetOriginalResponseAsync(options).ConfigureAwait(false); + + /// + async Task IDiscordInteraction.ModifyOriginalResponseAsync(Action func, RequestOptions options) + => await ModifyOriginalResponseAsync(func, options).ConfigureAwait(false); + #endregion + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/RestPingInteraction.cs b/src/Discord.Net.Rest/Entities/Interactions/RestPingInteraction.cs new file mode 100644 index 000000000..f979a4df2 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/RestPingInteraction.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Model = Discord.API.Interaction; + +namespace Discord.Rest +{ + /// + /// Represents a REST-based ping interaction. + /// + public class RestPingInteraction : RestInteraction, IDiscordInteraction + { + internal override bool _hasResponded { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + internal RestPingInteraction(BaseDiscordClient client, ulong id) + : base(client, id) + { + } + + internal static new async Task CreateAsync(DiscordRestClient client, Model model) + { + var entity = new RestPingInteraction(client, model.Id); + await entity.UpdateAsync(client, model); + return entity; + } + + public string AcknowledgePing() + { + var model = new API.InteractionResponse() + { + Type = InteractionResponseType.Pong + }; + + return SerializePayload(model); + } + + public override string Defer(bool ephemeral = false, RequestOptions options = null) => throw new NotSupportedException(); + public override Task FollowupAsync(string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null) => throw new NotSupportedException(); + public override Task FollowupWithFileAsync(Stream fileStream, string fileName, string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null) => throw new NotSupportedException(); + public override Task FollowupWithFileAsync(string filePath, string text = null, string fileName = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null) => throw new NotSupportedException(); + public override string Respond(string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null) => throw new NotSupportedException(); + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestAutocompleteInteraction.cs b/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestAutocompleteInteraction.cs new file mode 100644 index 000000000..3b879cd4e --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestAutocompleteInteraction.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Model = Discord.API.Interaction; +using DataModel = Discord.API.AutocompleteInteractionData; +using System.IO; + +namespace Discord.Rest +{ + /// + /// Represents a REST-based autocomplete interaction. + /// + public class RestAutocompleteInteraction : RestInteraction, IAutocompleteInteraction, IDiscordInteraction + { + /// + /// Gets the autocomplete data of this interaction. + /// + public new RestAutocompleteInteractionData Data { get; } + + internal override bool _hasResponded { get; set; } + private object _lock = new object(); + + internal RestAutocompleteInteraction(DiscordRestClient client, Model model) + : base(client, model.Id) + { + var dataModel = model.Data.IsSpecified + ? (DataModel)model.Data.Value + : null; + + if (dataModel != null) + Data = new RestAutocompleteInteractionData(dataModel); + } + + internal new static async Task CreateAsync(DiscordRestClient client, Model model) + { + var entity = new RestAutocompleteInteraction(client, model); + await entity.UpdateAsync(client, model).ConfigureAwait(false); + return entity; + } + + /// + /// Responds to this interaction with a set of choices. + /// + /// + /// The set of choices for the user to pick from. + /// + /// A max of 20 choices are allowed. Passing for this argument will show the executing user that + /// there is no choices for their autocompleted input. + /// + /// + /// The request options for this response. + /// + /// A string that contains json to write back to the incoming http request. + /// + public string Respond(IEnumerable result, RequestOptions options = null) + { + if (!InteractionHelper.CanSendResponse(this)) + throw new TimeoutException($"Cannot respond to an interaction after {InteractionHelper.ResponseTimeLimit} seconds!"); + + lock (_lock) + { + if (_hasResponded) + { + throw new InvalidOperationException("Cannot respond twice to the same interaction"); + } + } + + lock (_lock) + { + _hasResponded = true; + } + + var model = new API.InteractionResponse + { + Type = InteractionResponseType.ApplicationCommandAutocompleteResult, + Data = new API.InteractionCallbackData + { + Choices = result.Any() + ? result.Select(x => new API.ApplicationCommandOptionChoice { Name = x.Name, Value = x.Value }).ToArray() + : Array.Empty() + } + }; + + return SerializePayload(model); + } + + /// + /// Responds to this interaction with a set of choices. + /// + /// The request options for this response. + /// + /// The set of choices for the user to pick from. + /// + /// A max of 20 choices are allowed. Passing for this argument will show the executing user that + /// there is no choices for their autocompleted input. + /// + /// + /// + /// A string that contains json to write back to the incoming http request. + /// + public string Respond(RequestOptions options = null, params AutocompleteResult[] result) + => Respond(result, options); + + /// + [Obsolete("Autocomplete interactions cannot be deferred!", true)] + public override string Defer(bool ephemeral = false, RequestOptions options = null) + => throw new NotSupportedException("Autocomplete interactions cannot be deferred!"); + + /// + [Obsolete("Autocomplete interactions cannot have followups!", true)] + public override Task FollowupAsync(string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null) + => throw new NotSupportedException("Autocomplete interactions cannot be deferred!"); + + /// + [Obsolete("Autocomplete interactions cannot have followups!", true)] + public override Task FollowupWithFileAsync(Stream fileStream, string fileName, string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null) + => throw new NotSupportedException("Autocomplete interactions cannot be deferred!"); + + /// + [Obsolete("Autocomplete interactions cannot have followups!", true)] + public override Task FollowupWithFileAsync(string filePath, string text = null, string fileName = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null) + => throw new NotSupportedException("Autocomplete interactions cannot be deferred!"); + + /// + [Obsolete("Autocomplete interactions cannot have normal responses!", true)] + public override string Respond(string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null) + => throw new NotSupportedException("Autocomplete interactions cannot be deferred!"); + + //IAutocompleteInteraction + /// + IAutocompleteInteractionData IAutocompleteInteraction.Data => Data; + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestAutocompleteInteractionData.cs b/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestAutocompleteInteractionData.cs new file mode 100644 index 000000000..135eb88ea --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestAutocompleteInteractionData.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DataModel = Discord.API.AutocompleteInteractionData; + +namespace Discord.Rest +{ + /// + /// Represents the data for a . + /// + public class RestAutocompleteInteractionData : IAutocompleteInteractionData + { + /// + /// Gets the name of the invoked command. + /// + public string CommandName { get; } + + /// + /// Gets the id of the invoked command. + /// + public ulong CommandId { get; } + + /// + /// Gets the type of the invoked command. + /// + public ApplicationCommandType Type { get; } + + /// + /// Gets the version of the invoked command. + /// + public ulong Version { get; } + + /// + /// Gets the current autocomplete option that is actively being filled out. + /// + public AutocompleteOption Current { get; } + + /// + /// Gets a collection of all the other options the executing users has filled out. + /// + public IReadOnlyCollection Options { get; } + + internal RestAutocompleteInteractionData(DataModel model) + { + var options = model.Options.SelectMany(GetOptions); + + Current = options.FirstOrDefault(x => x.Focused); + Options = options.ToImmutableArray(); + + if (Options.Count == 1 && Current == null) + Current = Options.FirstOrDefault(); + + CommandName = model.Name; + CommandId = model.Id; + Type = model.Type; + Version = model.Version; + } + + private List GetOptions(API.AutocompleteInteractionDataOption model) + { + var options = new List(); + + options.Add(new AutocompleteOption(model.Type, model.Name, model.Value.GetValueOrDefault(null), model.Focused.GetValueOrDefault(false))); + + if (model.Options.IsSpecified) + { + options.AddRange(model.Options.Value.SelectMany(GetOptions)); + } + + return options; + } + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommand.cs b/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommand.cs new file mode 100644 index 000000000..785e39a12 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommand.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DataModel = Discord.API.ApplicationCommandInteractionData; +using Model = Discord.API.Interaction; + +namespace Discord.Rest +{ + /// + /// Represents a REST-based slash command. + /// + public class RestSlashCommand : RestCommandBase, ISlashCommandInteraction, IDiscordInteraction + { + /// + /// Gets the data associated with this interaction. + /// + public new RestSlashCommandData Data { get; private set; } + + internal RestSlashCommand(DiscordRestClient client, Model model) + : base(client, model) + { + } + + internal new static async Task CreateAsync(DiscordRestClient client, Model model) + { + var entity = new RestSlashCommand(client, model); + await entity.UpdateAsync(client, model).ConfigureAwait(false); + return entity; + } + + internal override async Task UpdateAsync(DiscordRestClient client, Model model) + { + await base.UpdateAsync(client, model).ConfigureAwait(false); + + var dataModel = model.Data.IsSpecified + ? (DataModel)model.Data.Value + : null; + + Data = await RestSlashCommandData.CreateAsync(client, dataModel, Guild, Channel).ConfigureAwait(false); + } + + //ISlashCommandInteraction + /// + IApplicationCommandInteractionData ISlashCommandInteraction.Data => Data; + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommandData.cs b/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommandData.cs new file mode 100644 index 000000000..f967cc628 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommandData.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Model = Discord.API.ApplicationCommandInteractionData; + +namespace Discord.Rest +{ + + public class RestSlashCommandData : RestCommandBaseData, IDiscordInteractionData + { + internal RestSlashCommandData(DiscordRestClient client, Model model) + : base(client, model) { } + + internal static new async Task CreateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel) + { + var entity = new RestSlashCommandData(client, model); + await entity.UpdateAsync(client, model, guild, channel).ConfigureAwait(false); + return entity; + } + internal override async Task UpdateAsync(DiscordRestClient client, Model model, RestGuild guild, IRestMessageChannel channel) + { + await base.UpdateAsync(client, model, guild, channel).ConfigureAwait(false); + + Options = model.Options.IsSpecified + ? model.Options.Value.Select(x => new RestSlashCommandDataOption(this, x)).ToImmutableArray() + : ImmutableArray.Create(); + } + } +} diff --git a/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommandDataOption.cs b/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommandDataOption.cs new file mode 100644 index 000000000..bb931f68e --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestSlashCommandDataOption.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Model = Discord.API.ApplicationCommandInteractionDataOption; + + +namespace Discord.Rest +{ + /// + /// Represents a REST-based option for a slash command. + /// + public class RestSlashCommandDataOption : IApplicationCommandInteractionDataOption + { + #region RestSlashCommandDataOption + /// + public string Name { get; private set; } + + /// + public object Value { get; private set; } + + /// + public ApplicationCommandOptionType Type { get; private set; } + + /// + /// Gets a collection of sub command options received for this sub command group. + /// + public IReadOnlyCollection Options { get; private set; } + + internal RestSlashCommandDataOption() { } + internal RestSlashCommandDataOption(RestSlashCommandData data, Model model) + { + Name = model.Name; + Type = model.Type; + + if (model.Value.IsSpecified) + { + switch (Type) + { + case ApplicationCommandOptionType.User: + case ApplicationCommandOptionType.Role: + case ApplicationCommandOptionType.Channel: + case ApplicationCommandOptionType.Mentionable: + if (ulong.TryParse($"{model.Value.Value}", out var valueId)) + { + switch (Type) + { + case ApplicationCommandOptionType.User: + { + var guildUser = data.ResolvableData.GuildMembers.FirstOrDefault(x => x.Key == valueId).Value; + + if (guildUser != null) + Value = guildUser; + else + Value = data.ResolvableData.Users.FirstOrDefault(x => x.Key == valueId).Value; + } + break; + case ApplicationCommandOptionType.Channel: + Value = data.ResolvableData.Channels.FirstOrDefault(x => x.Key == valueId).Value; + break; + case ApplicationCommandOptionType.Role: + Value = data.ResolvableData.Roles.FirstOrDefault(x => x.Key == valueId).Value; + break; + case ApplicationCommandOptionType.Mentionable: + { + if (data.ResolvableData.GuildMembers.Any(x => x.Key == valueId) || data.ResolvableData.Users.Any(x => x.Key == valueId)) + { + var guildUser = data.ResolvableData.GuildMembers.FirstOrDefault(x => x.Key == valueId).Value; + + if (guildUser != null) + Value = guildUser; + else + Value = data.ResolvableData.Users.FirstOrDefault(x => x.Key == valueId).Value; + } + else if (data.ResolvableData.Roles.Any(x => x.Key == valueId)) + { + Value = data.ResolvableData.Roles.FirstOrDefault(x => x.Key == valueId).Value; + } + } + break; + default: + Value = model.Value.Value; + break; + } + } + break; + case ApplicationCommandOptionType.String: + Value = model.Value.ToString(); + break; + case ApplicationCommandOptionType.Integer: + { + if (model.Value.Value is long val) + Value = val; + else if (long.TryParse(model.Value.Value.ToString(), out long res)) + Value = res; + } + break; + case ApplicationCommandOptionType.Boolean: + { + if (model.Value.Value is bool val) + Value = val; + else if (bool.TryParse(model.Value.Value.ToString(), out bool res)) + Value = res; + } + break; + case ApplicationCommandOptionType.Number: + { + if (model.Value.Value is int val) + Value = val; + else if (double.TryParse(model.Value.Value.ToString(), out double res)) + Value = res; + } + break; + } + } + + Options = model.Options.IsSpecified + ? model.Options.Value.Select(x => new RestSlashCommandDataOption(data, x)).ToImmutableArray() + : ImmutableArray.Create(); + } + #endregion + + #region Converters + public static explicit operator bool(RestSlashCommandDataOption option) + => (bool)option.Value; + public static explicit operator int(RestSlashCommandDataOption option) + => (int)option.Value; + public static explicit operator string(RestSlashCommandDataOption option) + => option.Value.ToString(); + #endregion + + #region IApplicationCommandInteractionDataOption + IReadOnlyCollection IApplicationCommandInteractionDataOption.Options + => Options; + #endregion + } +} diff --git a/src/Discord.Net.Rest/Entities/Messages/Attachment.cs b/src/Discord.Net.Rest/Entities/Messages/Attachment.cs index 1cd73518a..4e4849c51 100644 --- a/src/Discord.Net.Rest/Entities/Messages/Attachment.cs +++ b/src/Discord.Net.Rest/Entities/Messages/Attachment.cs @@ -21,8 +21,10 @@ public class Attachment : IAttachment public int? Height { get; } /// public int? Width { get; } + /// + public bool Ephemeral { get; } - internal Attachment(ulong id, string filename, string url, string proxyUrl, int size, int? height, int? width) + internal Attachment(ulong id, string filename, string url, string proxyUrl, int size, int? height, int? width, bool? ephemeral) { Id = id; Filename = filename; @@ -31,12 +33,14 @@ internal Attachment(ulong id, string filename, string url, string proxyUrl, int Size = size; Height = height; Width = width; + Ephemeral = ephemeral.GetValueOrDefault(false); } internal static Attachment Create(Model model) { return new Attachment(model.Id, model.Filename, model.Url, model.ProxyUrl, model.Size, model.Height.IsSpecified ? model.Height.Value : (int?)null, - model.Width.IsSpecified ? model.Width.Value : (int?)null); + model.Width.IsSpecified ? model.Width.Value : (int?)null, + model.Ephemeral.ToNullable()); } /// diff --git a/src/Discord.Net.Rest/Entities/Messages/CustomSticker.cs b/src/Discord.Net.Rest/Entities/Messages/CustomSticker.cs new file mode 100644 index 000000000..6fd0f7700 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Messages/CustomSticker.cs @@ -0,0 +1,74 @@ +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using Model = Discord.API.Sticker; + +namespace Discord.Rest +{ + /// + /// Represents a Rest-based custom sticker within a guild. + /// + [DebuggerDisplay(@"{DebuggerDisplay,nq}")] + public class CustomSticker : Sticker, ICustomSticker + { + /// + /// Gets the users id who uploaded the sticker. + /// + /// + /// In order to get the author id, the bot needs the MANAGE_EMOJIS_AND_STICKERS permission. + /// + public ulong? AuthorId { get; private set; } + + /// + /// Gets the guild that this custom sticker is in. + /// + /// + /// Note: This property can be if the sticker wasn't fetched from a guild. + /// + public RestGuild Guild { get; private set; } + + private ulong GuildId { get; set; } + + internal CustomSticker(BaseDiscordClient client, ulong id, RestGuild guild, ulong? authorId = null) + : base(client, id) + { + AuthorId = authorId; + Guild = guild; + } + internal CustomSticker(BaseDiscordClient client, ulong id, ulong guildId, ulong? authorId = null) + : base(client, id) + { + AuthorId = authorId; + GuildId = guildId; + } + + internal static CustomSticker Create(BaseDiscordClient client, Model model, RestGuild guild, ulong? authorId = null) + { + var entity = new CustomSticker(client, model.Id, guild, authorId); + entity.Update(model); + return entity; + } + + internal static CustomSticker Create(BaseDiscordClient client, Model model, ulong guildId, ulong? authorId = null) + { + var entity = new CustomSticker(client, model.Id, guildId, authorId); + entity.Update(model); + return entity; + } + + /// + public Task DeleteAsync(RequestOptions options = null) + => GuildHelper.DeleteStickerAsync(Discord, GuildId, this, options); + + /// + public async Task ModifyAsync(Action func, RequestOptions options = null) + { + var model = await GuildHelper.ModifyStickerAsync(Discord, GuildId, this, func, options); + Update(model); + } + + private string DebuggerDisplay => Guild != null ? $"{Name} in {Guild.Name} ({Id})" : $"{Name} ({Id})"; + + IGuild ICustomSticker.Guild => Guild; + } +} diff --git a/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs b/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs index 31252466b..309500c96 100644 --- a/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs +++ b/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs @@ -1,3 +1,4 @@ +using Discord.API; using Discord.API.Rest; using System; using System.Collections.Generic; @@ -24,18 +25,25 @@ internal static class MessageHelper /// Only the author of a message may modify the message. /// Message content is too long, length must be less or equal to . - public static async Task ModifyAsync(IMessage msg, BaseDiscordClient client, Action func, + public static Task ModifyAsync(IMessage msg, BaseDiscordClient client, Action func, + RequestOptions options) + => ModifyAsync(msg.Channel.Id, msg.Id, client, func, options); + + public static async Task ModifyAsync(ulong channelId, ulong msgId, BaseDiscordClient client, Action func, RequestOptions options) { var args = new MessageProperties(); func(args); - if (msg.Author.Id != client.CurrentUser.Id && (args.Content.IsSpecified || args.Embed.IsSpecified || args.AllowedMentions.IsSpecified)) - throw new InvalidOperationException("Only the author of a message may modify the message content, embed, or allowed mentions."); + var embed = args.Embed; + var embeds = args.Embeds; - bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : !string.IsNullOrEmpty(msg.Content); - bool hasEmbed = args.Embed.IsSpecified ? args.Embed.Value != null : msg.Embeds.Any(); - if (!hasText && !hasEmbed) + bool hasText = args.Content.IsSpecified && string.IsNullOrEmpty(args.Content.Value); + bool hasEmbeds = embed.IsSpecified && embed.Value != null || embeds.IsSpecified && embeds.Value?.Length > 0; + bool hasComponents = args.Components.IsSpecified && args.Components.Value != null; + bool hasAttachments = args.Attachments.IsSpecified; + + if (!hasComponents && !hasText && !hasEmbeds && !hasAttachments) Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); if (args.AllowedMentions.IsSpecified) @@ -43,6 +51,7 @@ public static async Task ModifyAsync(IMessage msg, BaseDiscordClient clie AllowedMentions allowedMentions = args.AllowedMentions.Value; Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(args.Embeds.Value?.Length ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); // check that user flag and user Id list are exclusive, same with role flag and role Id list if (allowedMentions != null && allowedMentions.AllowedTypes.HasValue) @@ -61,56 +70,45 @@ public static async Task ModifyAsync(IMessage msg, BaseDiscordClient clie } } - var apiArgs = new API.Rest.ModifyMessageParams + var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List() : null; + + if (embed.IsSpecified && embed.Value != null) { - Content = args.Content, - Embed = args.Embed.IsSpecified ? args.Embed.Value.ToModel() : Optional.Create(), - Flags = args.Flags.IsSpecified ? args.Flags.Value : Optional.Create(), - AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() : Optional.Create(), - }; - return await client.ApiClient.ModifyMessageAsync(msg.Channel.Id, msg.Id, apiArgs, options).ConfigureAwait(false); - } + apiEmbeds.Add(embed.Value.ToModel()); + } - public static async Task ModifyAsync(ulong channelId, ulong msgId, BaseDiscordClient client, Action func, - RequestOptions options) - { - var args = new MessageProperties(); - func(args); + if (embeds.IsSpecified && embeds.Value != null) + { + apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel())); + } - if ((args.Content.IsSpecified && string.IsNullOrEmpty(args.Content.Value)) && (args.Embed.IsSpecified && args.Embed.Value == null)) - Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); + Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); - if (args.AllowedMentions.IsSpecified) + if(!args.Attachments.IsSpecified) { - AllowedMentions allowedMentions = args.AllowedMentions.Value; - Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); - Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); - - // check that user flag and user Id list are exclusive, same with role flag and role Id list - if (allowedMentions != null && allowedMentions.AllowedTypes.HasValue) + var apiArgs = new API.Rest.ModifyMessageParams { - if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Users) && - allowedMentions.UserIds != null && allowedMentions.UserIds.Count > 0) - { - throw new ArgumentException("The Users flag is mutually exclusive with the list of User Ids.", nameof(allowedMentions)); - } - - if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Roles) && - allowedMentions.RoleIds != null && allowedMentions.RoleIds.Count > 0) - { - throw new ArgumentException("The Roles flag is mutually exclusive with the list of Role Ids.", nameof(allowedMentions)); - } - } + Content = args.Content, + Embeds = apiEmbeds?.ToArray() ?? Optional.Unspecified, + Flags = args.Flags.IsSpecified ? args.Flags.Value : Optional.Create(), + AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() : Optional.Create(), + Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Array.Empty() : Optional.Unspecified, + }; + return await client.ApiClient.ModifyMessageAsync(channelId, msgId, apiArgs, options).ConfigureAwait(false); } - - var apiArgs = new API.Rest.ModifyMessageParams + else { - Content = args.Content, - Embed = args.Embed.IsSpecified ? args.Embed.Value.ToModel() : Optional.Create(), - Flags = args.Flags.IsSpecified ? args.Flags.Value : Optional.Create(), - AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() : Optional.Create(), - }; - return await client.ApiClient.ModifyMessageAsync(channelId, msgId, apiArgs, options).ConfigureAwait(false); + var apiArgs = new UploadFileParams(args.Attachments.Value.ToArray()) + { + Content = args.Content, + Embeds = apiEmbeds?.ToArray() ?? Optional.Unspecified, + Flags = args.Flags.IsSpecified ? args.Flags.Value : Optional.Create(), + AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() : Optional.Create(), + MessageComponent = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Array.Empty() : Optional.Unspecified + }; + + return await client.ApiClient.ModifyMessageAsync(channelId, msgId, apiArgs, options).ConfigureAwait(false); + } } public static Task DeleteAsync(IMessage msg, BaseDiscordClient client, RequestOptions options) @@ -203,6 +201,12 @@ private static string UrlEncode(string text) return System.Web.HttpUtility.UrlEncode(text); #endif } + public static string SanitizeMessage(IMessage message) + { + var newContent = MentionUtils.Resolve(message, 0, TagHandling.FullName, TagHandling.FullName, TagHandling.FullName, TagHandling.FullName, TagHandling.FullName); + newContent = Format.StripMarkDown(newContent); + return newContent; + } public static async Task PinAsync(IMessage msg, BaseDiscordClient client, RequestOptions options) @@ -301,7 +305,7 @@ bool EnclosedInBlock(Match m) tags.Add(new Tag(TagType.Emoji, index, content.Length, emoji.Id, emoji)); else //Bad Tag { - index = index + 1; + index++; continue; } index = endIndex + 1; diff --git a/src/Discord.Net.Rest/Entities/Messages/RestFollowupMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestFollowupMessage.cs new file mode 100644 index 000000000..693d36e56 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Messages/RestFollowupMessage.cs @@ -0,0 +1,78 @@ +using System; +using System.Threading.Tasks; +using Model = Discord.API.Message; + +namespace Discord.Rest +{ + /// + /// Represents a REST-based follow up message sent by a bot responding to a slash command. + /// + public class RestFollowupMessage : RestUserMessage + { + // Token used to delete/modify this followup message + internal string Token { get; } + + internal RestFollowupMessage(BaseDiscordClient discord, ulong id, IUser author, string token, IMessageChannel channel) + : base(discord, id, channel, author, MessageSource.Bot) + { + Token = token; + } + + internal static RestFollowupMessage Create(BaseDiscordClient discord, Model model, string token, IMessageChannel channel) + { + var entity = new RestFollowupMessage(discord, model.Id, model.Author.IsSpecified ? RestUser.Create(discord, model.Author.Value) : discord.CurrentUser, token, channel); + entity.Update(model); + return entity; + } + + internal new void Update(Model model) + { + base.Update(model); + } + + /// + /// Deletes this object and all of it's children. + /// + /// A task that represents the asynchronous delete operation. + public Task DeleteAsync() + => InteractionHelper.DeleteFollowupMessageAsync(Discord, this); + + /// + /// Modifies this interaction followup message. + /// + /// + /// This method modifies this message with the specified properties. To see an example of this + /// method and what properties are available, please refer to . + /// + /// + /// The following example replaces the content of the message with Hello World!. + /// + /// await msg.ModifyAsync(x => x.Content = "Hello World!"); + /// + /// + /// A delegate containing the properties to modify the message with. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous modification operation. + /// + /// The token used to modify/delete this message expired. + /// /// Something went wrong during the request. + public new async Task ModifyAsync(Action func, RequestOptions options = null) + { + try + { + var model = await InteractionHelper.ModifyFollowupMessageAsync(Discord, this, func, options).ConfigureAwait(false); + Update(model); + } + catch (Net.HttpException x) + { + if (x.HttpCode == System.Net.HttpStatusCode.NotFound) + { + throw new InvalidOperationException("The token of this message has expired!", x); + } + + throw; + } + } + } +} diff --git a/src/Discord.Net.Rest/Entities/Messages/RestInteractionMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestInteractionMessage.cs new file mode 100644 index 000000000..26beb03b6 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Messages/RestInteractionMessage.cs @@ -0,0 +1,78 @@ +using System; +using System.Threading.Tasks; +using Model = Discord.API.Message; + +namespace Discord.Rest +{ + /// + /// Represents the initial REST-based response to a slash command. + /// + public class RestInteractionMessage : RestUserMessage + { + // Token used to delete/modify this followup message + internal string Token { get; } + + internal RestInteractionMessage(BaseDiscordClient discord, ulong id, IUser author, string token, IMessageChannel channel) + : base(discord, id, channel, author, MessageSource.Bot) + { + Token = token; + } + + internal static RestInteractionMessage Create(BaseDiscordClient discord, Model model, string token, IMessageChannel channel) + { + var entity = new RestInteractionMessage(discord, model.Id, model.Author.IsSpecified ? RestUser.Create(discord, model.Author.Value) : discord.CurrentUser, token, channel); + entity.Update(model); + return entity; + } + + internal new void Update(Model model) + { + base.Update(model); + } + + /// + /// Deletes this object and all of it's children. + /// + /// A task that represents the asynchronous delete operation. + public Task DeleteAsync() + => InteractionHelper.DeleteInteractionResponseAsync(Discord, this); + + /// + /// Modifies this interaction response + /// + /// + /// This method modifies this message with the specified properties. To see an example of this + /// method and what properties are available, please refer to . + /// + /// + /// The following example replaces the content of the message with Hello World!. + /// + /// await msg.ModifyAsync(x => x.Content = "Hello World!"); + /// + /// + /// A delegate containing the properties to modify the message with. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous modification operation. + /// + /// The token used to modify/delete this message expired. + /// /// Something went wrong during the request. + public new async Task ModifyAsync(Action func, RequestOptions options = null) + { + try + { + var model = await InteractionHelper.ModifyInteractionResponseAsync(Discord, Token, func, options).ConfigureAwait(false); + Update(model); + } + catch (Net.HttpException x) + { + if (x.HttpCode == System.Net.HttpStatusCode.NotFound) + { + throw new InvalidOperationException("The token of this message has expired!", x); + } + + throw; + } + } + } +} diff --git a/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs index 0c54743a6..c48a60aac 100644 --- a/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs +++ b/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs @@ -1,3 +1,4 @@ +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -14,6 +15,7 @@ public abstract class RestMessage : RestEntity, IMessage, IUpdateable { private long _timestampTicks; private ImmutableArray _reactions = ImmutableArray.Create(); + private ImmutableArray _userMentions = ImmutableArray.Create(); /// public IMessageChannel Channel { get; } @@ -27,6 +29,9 @@ public abstract class RestMessage : RestEntity, IMessage, IUpdateable /// public string Content { get; private set; } + /// + public string CleanContent => MessageHelper.SanitizeMessage(this); + /// public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); /// @@ -52,14 +57,10 @@ public abstract class RestMessage : RestEntity, IMessage, IUpdateable public virtual IReadOnlyCollection MentionedChannelIds => ImmutableArray.Create(); /// public virtual IReadOnlyCollection MentionedRoleIds => ImmutableArray.Create(); - /// - /// Gets a collection of the mentioned users in the message. - /// - public virtual IReadOnlyCollection MentionedUsers => ImmutableArray.Create(); /// public virtual IReadOnlyCollection Tags => ImmutableArray.Create(); /// - public virtual IReadOnlyCollection Stickers => ImmutableArray.Create(); + public virtual IReadOnlyCollection Stickers => ImmutableArray.Create(); /// public DateTimeOffset Timestamp => DateTimeUtils.FromTicks(_timestampTicks); @@ -69,11 +70,23 @@ public abstract class RestMessage : RestEntity, IMessage, IUpdateable public MessageApplication Application { get; private set; } /// public MessageReference Reference { get; private set; } + + /// + /// Gets the interaction this message is a response to. + /// + public MessageInteraction Interaction { get; private set; } /// public MessageFlags? Flags { get; private set; } /// public MessageType Type { get; private set; } + /// + public IReadOnlyCollection Components { get; private set; } + /// + /// Gets a collection of the mentioned users in the message. + /// + public IReadOnlyCollection MentionedUsers => _userMentions; + internal RestMessage(BaseDiscordClient discord, ulong id, IMessageChannel channel, IUser author, MessageSource source) : base(discord, id) { @@ -83,7 +96,10 @@ internal RestMessage(BaseDiscordClient discord, ulong id, IMessageChannel channe } internal static RestMessage Create(BaseDiscordClient discord, IMessageChannel channel, IUser author, Model model) { - if (model.Type == MessageType.Default || model.Type == MessageType.Reply) + if (model.Type == MessageType.Default || + model.Type == MessageType.Reply || + model.Type == MessageType.ApplicationCommand || + model.Type == MessageType.ThreadStarterMessage) return RestUserMessage.Create(discord, channel, author, model); else return RestSystemMessage.Create(discord, channel, author, model); @@ -121,7 +137,7 @@ internal virtual void Update(Model model) }; } - if(model.Reference.IsSpecified) + if (model.Reference.IsSpecified) { // Creates a new Reference from the API model Reference = new MessageReference @@ -132,6 +148,56 @@ internal virtual void Update(Model model) }; } + if (model.Components.IsSpecified) + { + Components = model.Components.Value.Select(x => new ActionRowComponent(x.Components.Select(y => + { + switch (y.Type) + { + case ComponentType.Button: + { + var parsed = (API.ButtonComponent)y; + return new Discord.ButtonComponent( + parsed.Style, + parsed.Label.GetValueOrDefault(), + parsed.Emote.IsSpecified + ? parsed.Emote.Value.Id.HasValue + ? new Emote(parsed.Emote.Value.Id.Value, parsed.Emote.Value.Name, parsed.Emote.Value.Animated.GetValueOrDefault()) + : new Emoji(parsed.Emote.Value.Name) + : null, + parsed.CustomId.GetValueOrDefault(), + parsed.Url.GetValueOrDefault(), + parsed.Disabled.GetValueOrDefault()); + } + case ComponentType.SelectMenu: + { + var parsed = (API.SelectMenuComponent)y; + return new SelectMenuComponent( + parsed.CustomId, + parsed.Options.Select(z => new SelectMenuOption( + z.Label, + z.Value, + z.Description.GetValueOrDefault(), + z.Emoji.IsSpecified + ? z.Emoji.Value.Id.HasValue + ? new Emote(z.Emoji.Value.Id.Value, z.Emoji.Value.Name, z.Emoji.Value.Animated.GetValueOrDefault()) + : new Emoji(z.Emoji.Value.Name) + : null, + z.Default.ToNullable())).ToList(), + parsed.Placeholder.GetValueOrDefault(), + parsed.MinValues, + parsed.MaxValues, + parsed.Disabled + ); + } + default: + return null; + } + }).ToList())).ToImmutableArray(); + } + else + Components = new List(); + if (model.Flags.IsSpecified) Flags = model.Flags.Value; @@ -150,8 +216,31 @@ internal virtual void Update(Model model) } else _reactions = ImmutableArray.Create(); - } + if (model.Interaction.IsSpecified) + { + Interaction = new MessageInteraction(model.Interaction.Value.Id, + model.Interaction.Value.Type, + model.Interaction.Value.Name, + RestUser.Create(Discord, model.Interaction.Value.User)); + } + + if (model.UserMentions.IsSpecified) + { + var value = model.UserMentions.Value; + if (value.Length > 0) + { + var newMentions = ImmutableArray.CreateBuilder(value.Length); + for (int i = 0; i < value.Length; i++) + { + var val = value[i]; + if (val != null) + newMentions.Add(RestUser.Create(Discord, val)); + } + _userMentions = newMentions.ToImmutable(); + } + } + } /// public async Task UpdateAsync(RequestOptions options = null) { @@ -177,8 +266,15 @@ public Task DeleteAsync(RequestOptions options = null) IReadOnlyCollection IMessage.Embeds => Embeds; /// IReadOnlyCollection IMessage.MentionedUserIds => MentionedUsers.Select(x => x.Id).ToImmutableArray(); + + /// + IReadOnlyCollection IMessage.Components => Components; + + /// + IMessageInteraction IMessage.Interaction => Interaction; + /// - IReadOnlyCollection IMessage.Stickers => Stickers; + IReadOnlyCollection IMessage.Stickers => Stickers; /// public IReadOnlyDictionary Reactions => _reactions.ToDictionary(x => x.Emote, x => new ReactionMetadata { ReactionCount = x.Count, IsMe = x.Me }); diff --git a/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs index aa6b44da6..083a8e72c 100644 --- a/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs +++ b/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs @@ -20,8 +20,7 @@ public class RestUserMessage : RestMessage, IUserMessage private ImmutableArray _embeds = ImmutableArray.Create(); private ImmutableArray _tags = ImmutableArray.Create(); private ImmutableArray _roleMentionIds = ImmutableArray.Create(); - private ImmutableArray _userMentions = ImmutableArray.Create(); - private ImmutableArray _stickers = ImmutableArray.Create(); + private ImmutableArray _stickers = ImmutableArray.Create(); /// public override bool IsTTS => _isTTS; @@ -42,11 +41,9 @@ public class RestUserMessage : RestMessage, IUserMessage /// public override IReadOnlyCollection MentionedRoleIds => _roleMentionIds; /// - public override IReadOnlyCollection MentionedUsers => _userMentions; - /// public override IReadOnlyCollection Tags => _tags; /// - public override IReadOnlyCollection Stickers => _stickers; + public override IReadOnlyCollection Stickers => _stickers; /// public IUserMessage ReferencedMessage => _referencedMessage; @@ -104,28 +101,12 @@ internal override void Update(Model model) _embeds = ImmutableArray.Create(); } - if (model.UserMentions.IsSpecified) - { - var value = model.UserMentions.Value; - if (value.Length > 0) - { - var newMentions = ImmutableArray.CreateBuilder(value.Length); - for (int i = 0; i < value.Length; i++) - { - var val = value[i]; - if (val.Object != null) - newMentions.Add(RestUser.Create(Discord, val.Object)); - } - _userMentions = newMentions.ToImmutable(); - } - } - var guildId = (Channel as IGuildChannel)?.GuildId; var guild = guildId != null ? (Discord as IDiscordClient).GetGuildAsync(guildId.Value, CacheMode.CacheOnly).Result : null; if (model.Content.IsSpecified) { var text = model.Content.Value; - _tags = MessageHelper.ParseTags(text, null, guild, _userMentions); + _tags = MessageHelper.ParseTags(text, null, guild, MentionedUsers); model.Content = text; } @@ -136,18 +117,18 @@ internal override void Update(Model model) _referencedMessage = RestUserMessage.Create(Discord, Channel, refMsgAuthor, refMsg); } - if (model.Stickers.IsSpecified) + if (model.StickerItems.IsSpecified) { - var value = model.Stickers.Value; + var value = model.StickerItems.Value; if (value.Length > 0) { - var stickers = ImmutableArray.CreateBuilder(value.Length); + var stickers = ImmutableArray.CreateBuilder(value.Length); for (int i = 0; i < value.Length; i++) - stickers.Add(Sticker.Create(value[i])); + stickers.Add(new StickerItem(Discord, value[i])); _stickers = stickers.ToImmutable(); } else - _stickers = ImmutableArray.Create(); + _stickers = ImmutableArray.Create(); } } diff --git a/src/Discord.Net.Rest/Entities/Messages/Sticker.cs b/src/Discord.Net.Rest/Entities/Messages/Sticker.cs index 5482bed74..accdbe66a 100644 --- a/src/Discord.Net.Rest/Entities/Messages/Sticker.cs +++ b/src/Discord.Net.Rest/Entities/Messages/Sticker.cs @@ -1,46 +1,55 @@ +using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using Model = Discord.API.Sticker; -namespace Discord +namespace Discord.Rest { /// [DebuggerDisplay(@"{DebuggerDisplay,nq}")] - public class Sticker : ISticker + public class Sticker : RestEntity, ISticker { /// - public ulong Id { get; } + public ulong PackId { get; protected set; } /// - public ulong PackId { get; } + public string Name { get; protected set; } /// - public string Name { get; } + public string Description { get; protected set; } /// - public string Description { get; } + public IReadOnlyCollection Tags { get; protected set; } /// - public IReadOnlyCollection Tags { get; } + public StickerType Type { get; protected set; } /// - public string Asset { get; } + public bool? IsAvailable { get; protected set; } /// - public string PreviewAsset { get; } + public int? SortOrder { get; protected set; } /// - public StickerFormatType FormatType { get; } + public StickerFormatType Format { get; protected set; } - internal Sticker(ulong id, ulong packId, string name, string description, string[] tags, string asset, string previewAsset, StickerFormatType formatType) + /// + public string GetStickerUrl() + => CDN.GetStickerUrl(Id, Format); + + internal Sticker(BaseDiscordClient client, ulong id) + : base(client, id) { } + internal static Sticker Create(BaseDiscordClient client, Model model) { - Id = id; - PackId = packId; - Name = name; - Description = description; - Tags = tags.ToReadOnlyCollection(); - Asset = asset; - PreviewAsset = previewAsset; - FormatType = formatType; + var entity = new Sticker(client, model.Id); + entity.Update(model); + return entity; } - internal static Sticker Create(Model model) + + internal void Update(Model model) { - return new Sticker(model.Id, model.PackId, model.Name, model.Desription, - model.Tags.IsSpecified ? model.Tags.Value.Split(',') : new string[0], - model.Asset, model.PreviewAsset, model.FormatType); + PackId = model.PackId; + Name = model.Name; + Description = model.Description; + Tags = model.Tags.IsSpecified ? model.Tags.Value.Split(',').Select(x => x.Trim()).ToArray() : Array.Empty(); + Type = model.Type; + SortOrder = model.SortValue; + IsAvailable = model.Available; + Format = model.FormatType; } private string DebuggerDisplay => $"{Name} ({Id})"; diff --git a/src/Discord.Net.Rest/Entities/Messages/StickerItem.cs b/src/Discord.Net.Rest/Entities/Messages/StickerItem.cs new file mode 100644 index 000000000..0ce4f634b --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Messages/StickerItem.cs @@ -0,0 +1,39 @@ +using System.Threading.Tasks; +using Model = Discord.API.StickerItem; + +namespace Discord.Rest +{ + /// + /// Represents a partial sticker received in a message. + /// + public class StickerItem : RestEntity, IStickerItem + { + /// + public string Name { get; } + + /// + public StickerFormatType Format { get; } + + internal StickerItem(BaseDiscordClient client, Model model) + : base(client, model.Id) + { + Name = model.Name; + Format = model.FormatType; + } + + /// + /// Resolves this sticker item by fetching the from the API. + /// + /// + /// A task representing the download operation, the result of the task is a sticker object. + /// + public async Task ResolveStickerAsync() + { + var model = await Discord.ApiClient.GetStickerAsync(Id); + + return model.GuildId.IsSpecified + ? CustomSticker.Create(Discord, model, model.GuildId.Value, model.User.IsSpecified ? model.User.Value.Id : null) + : Sticker.Create(Discord, model); + } + } +} diff --git a/src/Discord.Net.Rest/Entities/RestApplication.cs b/src/Discord.Net.Rest/Entities/RestApplication.cs index 5c2f872cf..beec52433 100644 --- a/src/Discord.Net.Rest/Entities/RestApplication.cs +++ b/src/Discord.Net.Rest/Entities/RestApplication.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.Threading.Tasks; using Model = Discord.API.Application; @@ -18,9 +20,9 @@ public class RestApplication : RestEntity, IApplication /// public string Description { get; private set; } /// - public string[] RPCOrigins { get; private set; } + public IReadOnlyCollection RPCOrigins { get; private set; } /// - public ulong Flags { get; private set; } + public ApplicationFlags Flags { get; private set; } /// public bool IsBotPublic { get; private set; } /// @@ -36,6 +38,10 @@ public class RestApplication : RestEntity, IApplication /// public string IconUrl => CDN.GetApplicationIconUrl(Id, _iconId); + public ApplicationInstallParams InstallParams { get; private set; } + + public IReadOnlyCollection Tags { get; private set; } + internal RestApplication(BaseDiscordClient discord, ulong id) : base(discord, id) { @@ -49,14 +55,17 @@ internal static RestApplication Create(BaseDiscordClient discord, Model model) internal void Update(Model model) { Description = model.Description; - RPCOrigins = model.RPCOrigins; + RPCOrigins = model.RPCOrigins.IsSpecified ? model.RPCOrigins.Value.ToImmutableArray() : ImmutableArray.Empty; Name = model.Name; _iconId = model.Icon; IsBotPublic = model.IsBotPublic; BotRequiresCodeGrant = model.BotRequiresCodeGrant; + Tags = model.Tags.GetValueOrDefault(null)?.ToImmutableArray() ?? ImmutableArray.Empty; + var installParams = model.InstallParams.GetValueOrDefault(null); + InstallParams = new ApplicationInstallParams(installParams?.Scopes ?? new string[0], (GuildPermission?)installParams?.Permission ?? null); if (model.Flags.IsSpecified) - Flags = model.Flags.Value; //TODO: Do we still need this? + Flags = model.Flags.Value; if (model.Owner.IsSpecified) Owner = RestUser.Create(Discord, model.Owner.Value); if (model.Team != null) diff --git a/src/Discord.Net.Rest/Entities/Roles/RestRole.cs b/src/Discord.Net.Rest/Entities/Roles/RestRole.cs index aa33ae7e5..a2ad4fd77 100644 --- a/src/Discord.Net.Rest/Entities/Roles/RestRole.cs +++ b/src/Discord.Net.Rest/Entities/Roles/RestRole.cs @@ -11,6 +11,7 @@ namespace Discord.Rest [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class RestRole : RestEntity, IRole { + #region RestRole internal IGuild Guild { get; } /// public Color Color { get; private set; } @@ -23,6 +24,10 @@ public class RestRole : RestEntity, IRole /// public string Name { get; private set; } /// + public string Icon { get; private set; } + /// /> + public Emoji Emoji { get; private set; } + /// public GuildPermissions Permissions { get; private set; } /// public int Position { get; private set; } @@ -60,11 +65,21 @@ internal void Update(Model model) Permissions = new GuildPermissions(model.Permissions); if (model.Tags.IsSpecified) Tags = model.Tags.Value.ToEntity(); + + if (model.Icon.IsSpecified) + { + Icon = model.Icon.Value; + } + + if (model.Emoji.IsSpecified) + { + Emoji = new Emoji(model.Emoji.Value); + } } /// public async Task ModifyAsync(Action func, RequestOptions options = null) - { + { var model = await RoleHelper.ModifyAsync(this, Discord, func, options).ConfigureAwait(false); Update(model); } @@ -72,6 +87,10 @@ public async Task ModifyAsync(Action func, RequestOptions option public Task DeleteAsync(RequestOptions options = null) => RoleHelper.DeleteAsync(this, Discord, options); + /// + public string GetIconUrl() + => CDN.GetGuildRoleIconUrl(Id, Icon); + /// public int CompareTo(IRole role) => RoleUtils.Compare(this, role); @@ -83,8 +102,9 @@ public Task DeleteAsync(RequestOptions options = null) /// public override string ToString() => Name; private string DebuggerDisplay => $"{Name} ({Id})"; + #endregion - //IRole + #region IRole /// IGuild IRole.Guild { @@ -95,5 +115,6 @@ IGuild IRole.Guild throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object."); } } + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Roles/RoleHelper.cs b/src/Discord.Net.Rest/Entities/Roles/RoleHelper.cs index 73ab7ca31..d8552f869 100644 --- a/src/Discord.Net.Rest/Entities/Roles/RoleHelper.cs +++ b/src/Discord.Net.Rest/Entities/Roles/RoleHelper.cs @@ -7,7 +7,7 @@ namespace Discord.Rest { internal static class RoleHelper { - //General + #region General public static async Task DeleteAsync(IRole role, BaseDiscordClient client, RequestOptions options) { @@ -18,13 +18,20 @@ public static async Task ModifyAsync(IRole role, BaseDiscordClient client { var args = new RoleProperties(); func(args); + + if (args.Icon.IsSpecified) + { + role.Guild.Features.EnsureFeature(GuildFeature.RoleIcons); + } + var apiArgs = new API.Rest.ModifyGuildRoleParams { Color = args.Color.IsSpecified ? args.Color.Value.RawValue : Optional.Create(), Hoist = args.Hoist, Mentionable = args.Mentionable, Name = args.Name, - Permissions = args.Permissions.IsSpecified ? args.Permissions.Value.RawValue.ToString() : Optional.Create() + Permissions = args.Permissions.IsSpecified ? args.Permissions.Value.RawValue.ToString() : Optional.Create(), + Icon = args.Icon.IsSpecified ? args.Icon.Value.ToModel() : Optional.Unspecified }; var model = await client.ApiClient.ModifyGuildRoleAsync(role.Guild.Id, role.Id, apiArgs, options).ConfigureAwait(false); @@ -36,5 +43,6 @@ public static async Task ModifyAsync(IRole role, BaseDiscordClient client } return model; } + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Users/RestGroupUser.cs b/src/Discord.Net.Rest/Entities/Users/RestGroupUser.cs index 55e9843eb..40e45b135 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestGroupUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestGroupUser.cs @@ -1,3 +1,4 @@ +using System; using System.Diagnostics; using Model = Discord.API.User; @@ -9,6 +10,7 @@ namespace Discord.Rest [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class RestGroupUser : RestUser, IGroupUser { + #region RestGroupUser internal RestGroupUser(BaseDiscordClient discord, ulong id) : base(discord, id) { @@ -19,8 +21,9 @@ internal RestGroupUser(BaseDiscordClient discord, ulong id) entity.Update(model); return entity; } +#endregion - //IVoiceState + #region IVoiceState /// bool IVoiceState.IsDeafened => false; /// @@ -37,5 +40,8 @@ internal RestGroupUser(BaseDiscordClient discord, ulong id) string IVoiceState.VoiceSessionId => null; /// bool IVoiceState.IsStreaming => false; + /// + DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null; + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs index 6e6bbe09c..2e184d32e 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestGuildUser.cs @@ -14,12 +14,15 @@ namespace Discord.Rest [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class RestGuildUser : RestUser, IGuildUser { + #region RestGuildUser private long? _premiumSinceTicks; private long? _joinedAtTicks; private ImmutableArray _roleIds; /// public string Nickname { get; private set; } + /// + public string GuildAvatarId { get; private set; } internal IGuild Guild { get; private set; } /// public bool IsDeafened { get; private set; } @@ -31,6 +34,18 @@ public class RestGuildUser : RestUser, IGuildUser public ulong GuildId => Guild.Id; /// public bool? IsPending { get; private set; } + /// + public int Hierarchy + { + get + { + if (Guild.OwnerId == Id) + return int.MaxValue; + + var orderedRoles = Guild.Roles.OrderByDescending(x => x.Position); + return orderedRoles.Where(x => RoleIds.Contains(x.Id)).Max(x => x.Position); + } + } /// /// Resolving permissions requires the parent guild to be downloaded. @@ -67,6 +82,8 @@ internal void Update(Model model) _joinedAtTicks = model.JoinedAt.Value.UtcTicks; if (model.Nick.IsSpecified) Nickname = model.Nick.Value; + if (model.Avatar.IsSpecified) + GuildAvatarId = model.Avatar.Value; if (model.Deaf.IsSpecified) IsDeafened = model.Deaf.Value; if (model.Mute.IsSpecified) @@ -144,7 +161,11 @@ public ChannelPermissions GetPermissions(IGuildChannel channel) return new ChannelPermissions(Permissions.ResolveChannel(Guild, this, channel, guildPerms.RawValue)); } - //IGuildUser + public string GetGuildAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) + => CDN.GetGuildUserAvatarUrl(Id, GuildId, GuildAvatarId, size, format); +#endregion + + #region IGuildUser /// IGuild IGuildUser.Guild { @@ -155,8 +176,9 @@ IGuild IGuildUser.Guild throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object."); } } + #endregion - //IVoiceState + #region IVoiceState /// bool IVoiceState.IsSelfDeafened => false; /// @@ -169,5 +191,8 @@ IGuild IGuildUser.Guild string IVoiceState.VoiceSessionId => null; /// bool IVoiceState.IsStreaming => false; + /// + DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null; + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Users/RestThreadUser.cs b/src/Discord.Net.Rest/Entities/Users/RestThreadUser.cs new file mode 100644 index 000000000..82830dafd --- /dev/null +++ b/src/Discord.Net.Rest/Entities/Users/RestThreadUser.cs @@ -0,0 +1,56 @@ +using System; +using System.Threading.Tasks; +using Model = Discord.API.ThreadMember; + +namespace Discord.Rest +{ + /// + /// Represents a thread user received over the REST api. + /// + public class RestThreadUser : RestEntity + { + /// + /// Gets the this user is in. + /// + public IThreadChannel Thread { get; } + + /// + /// Gets the timestamp for when this user joined this thread. + /// + public DateTimeOffset JoinedAt { get; private set; } + + /// + /// Gets the guild this user is in. + /// + public IGuild Guild { get; } + + internal RestThreadUser(BaseDiscordClient discord, IGuild guild, IThreadChannel channel, ulong id) + : base(discord, id) + { + Guild = guild; + Thread = channel; + } + + internal static RestThreadUser Create(BaseDiscordClient client, IGuild guild, Model model, IThreadChannel channel) + { + var entity = new RestThreadUser(client, guild, channel, model.UserId.Value); + entity.Update(model); + return entity; + } + + internal void Update(Model model) + { + JoinedAt = model.JoinTimestamp; + } + + /// + /// Gets the guild user for this thread user. + /// + /// + /// A task representing the asynchronous get operation. The task returns a + /// that represents the current thread user. + /// + public Task GetGuildUser() + => Guild.GetUserAsync(Id); + } +} diff --git a/src/Discord.Net.Rest/Entities/Users/RestUser.cs b/src/Discord.Net.Rest/Entities/Users/RestUser.cs index 7bc1447fe..872bab392 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestUser.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Threading.Tasks; using Model = Discord.API.User; +using EventUserModel = Discord.API.GuildScheduledEventUser; namespace Discord.Rest { @@ -13,6 +14,7 @@ namespace Discord.Rest [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class RestUser : RestEntity, IUser, IUpdateable { + #region RestUser /// public bool IsBot { get; private set; } /// @@ -22,6 +24,10 @@ public class RestUser : RestEntity, IUser, IUpdateable /// public string AvatarId { get; private set; } /// + public string BannerId { get; private set; } + /// + public Color? AccentColor { get; private set; } + /// public UserProperties? PublicFlags { get; private set; } /// @@ -57,10 +63,26 @@ internal static RestUser Create(BaseDiscordClient discord, IGuild guild, Model m entity.Update(model); return entity; } + internal static RestUser Create(BaseDiscordClient discord, IGuild guild, EventUserModel model) + { + if (model.Member.IsSpecified) + { + var member = model.Member.Value; + member.User = model.User; + return RestGuildUser.Create(discord, guild, member); + } + else + return RestUser.Create(discord, model.User); + } + internal virtual void Update(Model model) { if (model.Avatar.IsSpecified) AvatarId = model.Avatar.Value; + if (model.Banner.IsSpecified) + BannerId = model.Banner.Value; + if (model.AccentColor.IsSpecified) + AccentColor = model.AccentColor.Value; if (model.Discriminator.IsSpecified) DiscriminatorValue = ushort.Parse(model.Discriminator.Value, NumberStyles.None, CultureInfo.InvariantCulture); if (model.Bot.IsSpecified) @@ -92,6 +114,10 @@ public Task CreateDMChannelAsync(RequestOptions options = null) public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) => CDN.GetUserAvatarUrl(Id, AvatarId, size, format); + /// + public string GetBannerUrl(ImageFormat format = ImageFormat.Auto, ushort size = 256) + => CDN.GetUserBannerUrl(Id, BannerId, size, format); + /// public string GetDefaultAvatarUrl() => CDN.GetDefaultUserAvatarUrl(DiscriminatorValue); @@ -104,10 +130,12 @@ public string GetDefaultAvatarUrl() /// public override string ToString() => $"{Username}#{Discriminator}"; private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")})"; + #endregion - //IUser + #region IUser /// async Task IUser.CreateDMChannelAsync(RequestOptions options) => await CreateDMChannelAsync(options).ConfigureAwait(false); + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Users/RestWebhookUser.cs b/src/Discord.Net.Rest/Entities/Users/RestWebhookUser.cs index 2131fec93..2cd19da41 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestWebhookUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestWebhookUser.cs @@ -10,6 +10,7 @@ namespace Discord.Rest [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class RestWebhookUser : RestUser, IWebhookUser { + #region RestWebhookUser /// public ulong WebhookId { get; } internal IGuild Guild { get; } @@ -33,8 +34,9 @@ internal static RestWebhookUser Create(BaseDiscordClient discord, IGuild guild, entity.Update(model); return entity; } +#endregion - //IGuildUser + #region IGuildUser /// IGuild IGuildUser.Guild { @@ -52,8 +54,14 @@ IGuild IGuildUser.Guild /// string IGuildUser.Nickname => null; /// + string IGuildUser.GuildAvatarId => null; + /// + string IGuildUser.GetGuildAvatarUrl(ImageFormat format, ushort size) => null; + /// bool? IGuildUser.IsPending => null; /// + int IGuildUser.Hierarchy => 0; + /// GuildPermissions IGuildUser.GuildPermissions => GuildPermissions.Webhook; /// @@ -89,8 +97,9 @@ Task IGuildUser.RemoveRolesAsync(IEnumerable roles, RequestOptions option /// Task IGuildUser.RemoveRolesAsync(IEnumerable roles, RequestOptions options) => throw new NotSupportedException("Roles are not supported on webhook users."); + #endregion - //IVoiceState + #region IVoiceState /// bool IVoiceState.IsDeafened => false; /// @@ -107,5 +116,8 @@ Task IGuildUser.RemoveRolesAsync(IEnumerable roles, RequestOptions option string IVoiceState.VoiceSessionId => null; /// bool IVoiceState.IsStreaming => false; + /// + DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null; + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs b/src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs index 9baddf003..f40b786cd 100644 --- a/src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs +++ b/src/Discord.Net.Rest/Entities/Webhooks/RestWebhook.cs @@ -8,6 +8,7 @@ namespace Discord.Rest [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class RestWebhook : RestEntity, IWebhook, IUpdateable { + #region RestWebhook internal IGuild Guild { get; private set; } internal ITextChannel Channel { get; private set; } @@ -24,6 +25,8 @@ public class RestWebhook : RestEntity, IWebhook, IUpdateable public ulong? GuildId { get; private set; } /// public IUser Creator { get; private set; } + /// + public ulong? ApplicationId { get; private set; } /// public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); @@ -66,6 +69,8 @@ internal void Update(Model model) GuildId = model.GuildId.Value; if (model.Name.IsSpecified) Name = model.Name.Value; + + ApplicationId = model.ApplicationId; } /// @@ -91,8 +96,9 @@ public Task DeleteAsync(RequestOptions options = null) public override string ToString() => $"Webhook: {Name}:{Id}"; private string DebuggerDisplay => $"Webhook: {Name} ({Id})"; + #endregion - //IWebhook + #region IWebhook /// IGuild IWebhook.Guild => Guild ?? throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object."); @@ -102,5 +108,6 @@ ITextChannel IWebhook.Channel /// Task IWebhook.ModifyAsync(Action func, RequestOptions options) => ModifyAsync(func, options); + #endregion } } diff --git a/src/Discord.Net.Rest/Entities/Webhooks/WebhookHelper.cs b/src/Discord.Net.Rest/Entities/Webhooks/WebhookHelper.cs index 50e9cab78..0b61b6c22 100644 --- a/src/Discord.Net.Rest/Entities/Webhooks/WebhookHelper.cs +++ b/src/Discord.Net.Rest/Entities/Webhooks/WebhookHelper.cs @@ -33,6 +33,5 @@ public static async Task DeleteAsync(IWebhook webhook, BaseDiscordClient client, { await client.ApiClient.DeleteWebhookAsync(webhook.Id, options).ConfigureAwait(false); } - } } diff --git a/src/Discord.Net.Rest/Extensions/EntityExtensions.cs b/src/Discord.Net.Rest/Extensions/EntityExtensions.cs index f8676c783..61fe330df 100644 --- a/src/Discord.Net.Rest/Extensions/EntityExtensions.cs +++ b/src/Discord.Net.Rest/Extensions/EntityExtensions.cs @@ -39,7 +39,7 @@ public static RoleTags ToEntity(this API.RoleTags model) return new RoleTags( model.BotId.IsSpecified ? model.BotId.Value : null, model.IntegrationId.IsSpecified ? model.IntegrationId.Value : null, - model.IsPremiumSubscriber.IsSpecified ? true : false); + model.IsPremiumSubscriber.GetValueOrDefault(false) ?? false); } public static API.Embed ToModel(this Embed entity) { @@ -68,6 +68,7 @@ public static API.Embed ToModel(this Embed entity) model.Video = entity.Video.Value.ToModel(); return model; } + public static API.AllowedMentions ToModel(this AllowedMentions entity) { return new API.AllowedMentions() diff --git a/src/Discord.Net.Rest/Net/BadSignatureException.cs b/src/Discord.Net.Rest/Net/BadSignatureException.cs new file mode 100644 index 000000000..08672df8e --- /dev/null +++ b/src/Discord.Net.Rest/Net/BadSignatureException.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.Rest +{ + public class BadSignatureException : Exception + { + internal BadSignatureException() : base("Failed to verify authenticity of message: public key doesnt match signature") + { + + } + } +} diff --git a/src/Discord.Net.Rest/Net/Converters/ArrayConverter.cs b/src/Discord.Net.Rest/Net/Converters/ArrayConverter.cs index 3cededb7b..ce2e9b1f7 100644 --- a/src/Discord.Net.Rest/Net/Converters/ArrayConverter.cs +++ b/src/Discord.Net.Rest/Net/Converters/ArrayConverter.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; using System; using System.Collections.Generic; diff --git a/src/Discord.Net.Rest/Net/Converters/DiscordContractResolver.cs b/src/Discord.Net.Rest/Net/Converters/DiscordContractResolver.cs index 931c0c4c9..91ba22460 100644 --- a/src/Discord.Net.Rest/Net/Converters/DiscordContractResolver.cs +++ b/src/Discord.Net.Rest/Net/Converters/DiscordContractResolver.cs @@ -10,9 +10,10 @@ namespace Discord.Net.Converters { internal class DiscordContractResolver : DefaultContractResolver { + #region DiscordContractResolver private static readonly TypeInfo _ienumerable = typeof(IEnumerable).GetTypeInfo(); - private static readonly MethodInfo _shouldSerialize = typeof(DiscordContractResolver).GetTypeInfo().GetDeclaredMethod("ShouldSerialize"); - + private static readonly MethodInfo _shouldSerialize = typeof(DiscordContractResolver).GetTypeInfo().GetDeclaredMethod("ShouldSerialize"); + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { var property = base.CreateProperty(member, memberSerialization); @@ -57,8 +58,9 @@ private static JsonConverter GetConverter(JsonProperty property, PropertyInfo pr else if (genericType == typeof(EntityOrId<>)) return MakeGenericConverter(property, propInfo, typeof(UInt64EntityOrIdConverter<>), type.GenericTypeArguments[0], depth); } + #endregion - //Primitives + #region Primitives bool hasInt53 = propInfo.GetCustomAttribute() != null; if (!hasInt53) { @@ -81,6 +83,14 @@ private static JsonConverter GetConverter(JsonProperty property, PropertyInfo pr //Special if (type == typeof(API.Image)) return ImageConverter.Instance; + if (typeof(IMessageComponent).IsAssignableFrom(type)) + return MessageComponentConverter.Instance; + if (type == typeof(API.Interaction)) + return InteractionConverter.Instance; + if (type == typeof(API.DiscordError)) + return DiscordErrorConverter.Instance; + if (type == typeof(GuildFeatures)) + return GuildFeaturesConverter.Instance; //Entities var typeInfo = type.GetTypeInfo(); @@ -103,5 +113,6 @@ private static JsonConverter MakeGenericConverter(JsonProperty property, Propert var innerConverter = GetConverter(property, propInfo, innerType, depth + 1); return genericType.DeclaredConstructors.First().Invoke(new object[] { innerConverter }) as JsonConverter; } + #endregion } } diff --git a/src/Discord.Net.Rest/Net/Converters/DiscordErrorConverter.cs b/src/Discord.Net.Rest/Net/Converters/DiscordErrorConverter.cs new file mode 100644 index 000000000..772ddc6b2 --- /dev/null +++ b/src/Discord.Net.Rest/Net/Converters/DiscordErrorConverter.cs @@ -0,0 +1,88 @@ +using Discord.API; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.Net.Converters +{ + internal class DiscordErrorConverter : JsonConverter + { + public static DiscordErrorConverter Instance + => new DiscordErrorConverter(); + + public override bool CanConvert(Type objectType) => objectType == typeof(DiscordError); + + public override bool CanRead => true; + public override bool CanWrite => false; + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var obj = JObject.Load(reader); + var err = new API.DiscordError(); + + + var result = obj.GetValue("errors", StringComparison.OrdinalIgnoreCase); + result?.Parent.Remove(); + + // Populate the remaining properties. + using (var subReader = obj.CreateReader()) + { + serializer.Populate(subReader, err); + } + + if (result != null) + { + var innerReader = result.CreateReader(); + + var errors = ReadErrors(innerReader); + err.Errors = errors.ToArray(); + } + + return err; + } + + private List ReadErrors(JsonReader reader, string path = "") + { + List errs = new List(); + var obj = JObject.Load(reader); + var props = obj.Properties(); + foreach (var prop in props) + { + if (prop.Name == "_errors" && path == "") // root level error + { + errs.Add(new ErrorDetails() + { + Name = Optional.Unspecified, + Errors = prop.Value.ToObject() + }); + } + else if (prop.Name == "_errors") // path errors (not root level) + { + errs.Add(new ErrorDetails() + { + Name = path, + Errors = prop.Value.ToObject() + }); + } + else if(int.TryParse(prop.Name, out var i)) // array value + { + var r = prop.Value.CreateReader(); + errs.AddRange(ReadErrors(r, path + $"[{i}]")); + } + else // property name + { + var r = prop.Value.CreateReader(); + errs.AddRange(ReadErrors(r, path + $"{(path != "" ? "." : "")}{prop.Name[0].ToString().ToUpper() + new string(prop.Name.Skip(1).ToArray())}")); + } + } + + return errs; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException(); + } +} diff --git a/src/Discord.Net.Rest/Net/Converters/EmbedTypeConverter.cs b/src/Discord.Net.Rest/Net/Converters/EmbedTypeConverter.cs index 1e03fb698..cacd2e2e1 100644 --- a/src/Discord.Net.Rest/Net/Converters/EmbedTypeConverter.cs +++ b/src/Discord.Net.Rest/Net/Converters/EmbedTypeConverter.cs @@ -13,28 +13,19 @@ internal class EmbedTypeConverter : JsonConverter public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - switch ((string)reader.Value) + return (string)reader.Value switch { - case "rich": - return EmbedType.Rich; - case "link": - return EmbedType.Link; - case "video": - return EmbedType.Video; - case "image": - return EmbedType.Image; - case "gifv": - return EmbedType.Gifv; - case "article": - return EmbedType.Article; - case "tweet": - return EmbedType.Tweet; - case "html": - return EmbedType.Html; - case "application_news": // TODO 2.2 EmbedType.News - default: - return EmbedType.Unknown; - } + "rich" => EmbedType.Rich, + "link" => EmbedType.Link, + "video" => EmbedType.Video, + "image" => EmbedType.Image, + "gifv" => EmbedType.Gifv, + "article" => EmbedType.Article, + "tweet" => EmbedType.Tweet, + "html" => EmbedType.Html, + // TODO 2.2 EmbedType.News + _ => EmbedType.Unknown, + }; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) diff --git a/src/Discord.Net.Rest/Net/Converters/GuildFeaturesConverter.cs b/src/Discord.Net.Rest/Net/Converters/GuildFeaturesConverter.cs new file mode 100644 index 000000000..9f82b440b --- /dev/null +++ b/src/Discord.Net.Rest/Net/Converters/GuildFeaturesConverter.cs @@ -0,0 +1,60 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Discord.Net.Converters +{ + internal class GuildFeaturesConverter : JsonConverter + { + public static GuildFeaturesConverter Instance + => new GuildFeaturesConverter(); + + public override bool CanConvert(Type objectType) => true; + public override bool CanWrite => false; + public override bool CanRead => true; + + + private Regex _readRegex = new Regex(@"_(\w)"); + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var obj = JToken.Load(reader); + var arr = obj.ToObject(); + + GuildFeature features = GuildFeature.None; + List experimental = new(); + + foreach(var item in arr) + { + var name = _readRegex.Replace(item.ToLower(), (x) => + { + return x.Groups[1].Value.ToUpper(); + }); + + name = name[0].ToString().ToUpper() + new string(name.Skip(1).ToArray()); + + try + { + var result = (GuildFeature)Enum.Parse(typeof(GuildFeature), name); + + features |= result; + } + catch + { + experimental.Add(item); + } + } + + return new GuildFeatures(features, experimental.ToArray()); + } + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Discord.Net.Rest/Net/Converters/InteractionConverter.cs b/src/Discord.Net.Rest/Net/Converters/InteractionConverter.cs new file mode 100644 index 000000000..f7235841d --- /dev/null +++ b/src/Discord.Net.Rest/Net/Converters/InteractionConverter.cs @@ -0,0 +1,70 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; + +namespace Discord.Net.Converters +{ + internal class InteractionConverter : JsonConverter + { + public static InteractionConverter Instance => new InteractionConverter(); + + public override bool CanRead => true; + public override bool CanWrite => false; + public override bool CanConvert(Type objectType) => true; + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + return null; + + var obj = JObject.Load(reader); + var interaction = new API.Interaction(); + + + // Remove the data property for manual deserialization + var result = obj.GetValue("data", StringComparison.OrdinalIgnoreCase); + result?.Parent.Remove(); + + // Populate the remaining properties. + using (var subReader = obj.CreateReader()) + { + serializer.Populate(subReader, interaction); + } + + // Process the Result property + if (result != null) + { + switch (interaction.Type) + { + case InteractionType.ApplicationCommand: + { + var appCommandData = new API.ApplicationCommandInteractionData(); + serializer.Populate(result.CreateReader(), appCommandData); + interaction.Data = appCommandData; + } + break; + case InteractionType.MessageComponent: + { + var messageComponent = new API.MessageComponentInteractionData(); + serializer.Populate(result.CreateReader(), messageComponent); + interaction.Data = messageComponent; + } + break; + case InteractionType.ApplicationCommandAutocomplete: + { + var autocompleteData = new API.AutocompleteInteractionData(); + serializer.Populate(result.CreateReader(), autocompleteData); + interaction.Data = autocompleteData; + } + break; + } + } + else + interaction.Data = Optional.Unspecified; + + return interaction; + } + + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException(); + } +} diff --git a/src/Discord.Net.Rest/Net/Converters/MessageComponentConverter.cs b/src/Discord.Net.Rest/Net/Converters/MessageComponentConverter.cs new file mode 100644 index 000000000..0bf11a369 --- /dev/null +++ b/src/Discord.Net.Rest/Net/Converters/MessageComponentConverter.cs @@ -0,0 +1,40 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; + +namespace Discord.Net.Converters +{ + internal class MessageComponentConverter : JsonConverter + { + public static MessageComponentConverter Instance => new MessageComponentConverter(); + + public override bool CanRead => true; + public override bool CanWrite => false; + public override bool CanConvert(Type objectType) => true; + public override void WriteJson(JsonWriter writer, + object value, JsonSerializer serializer) + { + serializer.Serialize(writer, value); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var jsonObject = JObject.Load(reader); + var messageComponent = default(IMessageComponent); + switch ((ComponentType)jsonObject["type"].Value()) + { + case ComponentType.ActionRow: + messageComponent = new API.ActionRowComponent(); + break; + case ComponentType.Button: + messageComponent = new API.ButtonComponent(); + break; + case ComponentType.SelectMenu: + messageComponent = new API.SelectMenuComponent(); + break; + } + serializer.Populate(jsonObject.CreateReader(), messageComponent); + return messageComponent; + } + } +} diff --git a/src/Discord.Net.Rest/Net/Converters/UnixTimestampConverter.cs b/src/Discord.Net.Rest/Net/Converters/UnixTimestampConverter.cs index 0b50cb166..876254fb9 100644 --- a/src/Discord.Net.Rest/Net/Converters/UnixTimestampConverter.cs +++ b/src/Discord.Net.Rest/Net/Converters/UnixTimestampConverter.cs @@ -27,7 +27,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - throw new NotImplementedException(); + writer.WriteValue(((DateTimeOffset)value).ToString("O")); } } } diff --git a/src/Discord.Net.Rest/Net/Converters/UserStatusConverter.cs b/src/Discord.Net.Rest/Net/Converters/UserStatusConverter.cs index c0a287c16..8a13e79a5 100644 --- a/src/Discord.Net.Rest/Net/Converters/UserStatusConverter.cs +++ b/src/Discord.Net.Rest/Net/Converters/UserStatusConverter.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; using System; namespace Discord.Net.Converters @@ -13,21 +13,15 @@ internal class UserStatusConverter : JsonConverter public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - switch ((string)reader.Value) + return (string)reader.Value switch { - case "online": - return UserStatus.Online; - case "idle": - return UserStatus.Idle; - case "dnd": - return UserStatus.DoNotDisturb; - case "invisible": - return UserStatus.Invisible; //Should never happen - case "offline": - return UserStatus.Offline; - default: - throw new JsonSerializationException("Unknown user status"); - } + "online" => UserStatus.Online, + "idle" => UserStatus.Idle, + "dnd" => UserStatus.DoNotDisturb, + "invisible" => UserStatus.Invisible,//Should never happen + "offline" => UserStatus.Offline, + _ => throw new JsonSerializationException("Unknown user status"), + }; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) diff --git a/src/Discord.Net.Rest/Net/DefaultRestClient.cs b/src/Discord.Net.Rest/Net/DefaultRestClient.cs index b5036d94e..1db743609 100644 --- a/src/Discord.Net.Rest/Net/DefaultRestClient.cs +++ b/src/Discord.Net.Rest/Net/DefaultRestClient.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Http.Headers; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -101,7 +102,7 @@ public async Task SendAsync(string method, string endpoint, IReadO switch (p.Value) { #pragma warning disable IDISP004 - case string stringValue: { content.Add(new StringContent(stringValue), p.Key); continue; } + case string stringValue: { content.Add(new StringContent(stringValue, Encoding.UTF8, "text/plain"), p.Key); continue; } case byte[] byteArrayValue: { content.Add(new ByteArrayContent(byteArrayValue), p.Key); continue; } case Stream streamValue: { content.Add(new StreamContent(streamValue), p.Key); continue; } case MultipartFile fileValue: @@ -116,8 +117,16 @@ public async Task SendAsync(string method, string endpoint, IReadO stream = memoryStream; #pragma warning restore IDISP001 } - content.Add(new StreamContent(stream), p.Key, fileValue.Filename); + + var streamContent = new StreamContent(stream); + var extension = fileValue.Filename.Split('.').Last(); + + if(fileValue.ContentType != null) + streamContent.Headers.ContentType = new MediaTypeHeaderValue(fileValue.ContentType); + + content.Add(streamContent, p.Key, fileValue.Filename); #pragma warning restore IDISP004 + continue; } default: throw new InvalidOperationException($"Unsupported param type \"{p.Value.GetType().Name}\"."); @@ -148,15 +157,15 @@ private async Task SendInternalAsync(HttpRequestMessage request, C private static readonly HttpMethod Patch = new HttpMethod("PATCH"); private HttpMethod GetMethod(string method) { - switch (method) + return method switch { - case "DELETE": return HttpMethod.Delete; - case "GET": return HttpMethod.Get; - case "PATCH": return Patch; - case "POST": return HttpMethod.Post; - case "PUT": return HttpMethod.Put; - default: throw new ArgumentOutOfRangeException(nameof(method), $"Unknown HttpMethod: {method}"); - } + "DELETE" => HttpMethod.Delete, + "GET" => HttpMethod.Get, + "PATCH" => Patch, + "POST" => HttpMethod.Post, + "PUT" => HttpMethod.Put, + _ => throw new ArgumentOutOfRangeException(nameof(method), $"Unknown HttpMethod: {method}"), + }; } } } diff --git a/src/Discord.Net.Rest/Net/ED25519/Array16.cs b/src/Discord.Net.Rest/Net/ED25519/Array16.cs new file mode 100644 index 000000000..fca8616c5 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Array16.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; + +namespace Discord.Net.ED25519 +{ + // Array16 Salsa20 state + // Array16 SHA-512 block + internal struct Array16 + { + public T x0; + public T x1; + public T x2; + public T x3; + public T x4; + public T x5; + public T x6; + public T x7; + public T x8; + public T x9; + public T x10; + public T x11; + public T x12; + public T x13; + public T x14; + public T x15; + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Array8.cs b/src/Discord.Net.Rest/Net/ED25519/Array8.cs new file mode 100644 index 000000000..b563ac213 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Array8.cs @@ -0,0 +1,18 @@ +using System; + +namespace Discord.Net.ED25519 +{ + // Array8 Poly1305 key + // Array8 SHA-512 state/output + internal struct Array8 + { + public T x0; + public T x1; + public T x2; + public T x3; + public T x4; + public T x5; + public T x6; + public T x7; + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/ByteIntegerConverter.cs b/src/Discord.Net.Rest/Net/ED25519/ByteIntegerConverter.cs new file mode 100644 index 000000000..40c7624ba --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/ByteIntegerConverter.cs @@ -0,0 +1,55 @@ +using System; + +namespace Discord.Net.ED25519 +{ + // Loops? Arrays? Never heard of that stuff + // Library avoids unnecessary heap allocations and unsafe code + // so this ugly code becomes necessary :( + internal static class ByteIntegerConverter + { + public static ulong LoadBigEndian64(byte[] buf, int offset) + { + return + (ulong)(buf[offset + 7]) + | (((ulong)(buf[offset + 6])) << 8) + | (((ulong)(buf[offset + 5])) << 16) + | (((ulong)(buf[offset + 4])) << 24) + | (((ulong)(buf[offset + 3])) << 32) + | (((ulong)(buf[offset + 2])) << 40) + | (((ulong)(buf[offset + 1])) << 48) + | (((ulong)(buf[offset + 0])) << 56); + } + + public static void StoreBigEndian64(byte[] buf, int offset, ulong value) + { + buf[offset + 7] = unchecked((byte)value); + buf[offset + 6] = unchecked((byte)(value >> 8)); + buf[offset + 5] = unchecked((byte)(value >> 16)); + buf[offset + 4] = unchecked((byte)(value >> 24)); + buf[offset + 3] = unchecked((byte)(value >> 32)); + buf[offset + 2] = unchecked((byte)(value >> 40)); + buf[offset + 1] = unchecked((byte)(value >> 48)); + buf[offset + 0] = unchecked((byte)(value >> 56)); + } + + public static void Array16LoadBigEndian64(out Array16 output, byte[] input, int inputOffset) + { + output.x0 = LoadBigEndian64(input, inputOffset + 0); + output.x1 = LoadBigEndian64(input, inputOffset + 8); + output.x2 = LoadBigEndian64(input, inputOffset + 16); + output.x3 = LoadBigEndian64(input, inputOffset + 24); + output.x4 = LoadBigEndian64(input, inputOffset + 32); + output.x5 = LoadBigEndian64(input, inputOffset + 40); + output.x6 = LoadBigEndian64(input, inputOffset + 48); + output.x7 = LoadBigEndian64(input, inputOffset + 56); + output.x8 = LoadBigEndian64(input, inputOffset + 64); + output.x9 = LoadBigEndian64(input, inputOffset + 72); + output.x10 = LoadBigEndian64(input, inputOffset + 80); + output.x11 = LoadBigEndian64(input, inputOffset + 88); + output.x12 = LoadBigEndian64(input, inputOffset + 96); + output.x13 = LoadBigEndian64(input, inputOffset + 104); + output.x14 = LoadBigEndian64(input, inputOffset + 112); + output.x15 = LoadBigEndian64(input, inputOffset + 120); + } + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/CryptoBytes.cs b/src/Discord.Net.Rest/Net/ED25519/CryptoBytes.cs new file mode 100644 index 000000000..cfd64104d --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/CryptoBytes.cs @@ -0,0 +1,272 @@ +using System; +using System.Linq; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Discord.Net.ED25519 +{ + internal class CryptoBytes + { + /// + /// Comparison of two arrays. + /// + /// The runtime of this method does not depend on the contents of the arrays. Using constant time + /// prevents timing attacks that allow an attacker to learn if the arrays have a common prefix. + /// + /// It is important to use such a constant time comparison when verifying MACs. + /// + /// Byte array + /// Byte array + /// True if arrays are equal + public static bool ConstantTimeEquals(byte[] x, byte[] y) + { + if (x.Length != y.Length) + return false; + return InternalConstantTimeEquals(x, 0, y, 0, x.Length) != 0; + } + + /// + /// Comparison of two array segments. + /// + /// The runtime of this method does not depend on the contents of the arrays. Using constant time + /// prevents timing attacks that allow an attacker to learn if the arrays have a common prefix. + /// + /// It is important to use such a constant time comparison when verifying MACs. + /// + /// Byte array segment + /// Byte array segment + /// True if contents of x and y are equal + public static bool ConstantTimeEquals(ArraySegment x, ArraySegment y) + { + if (x.Count != y.Count) + return false; + return InternalConstantTimeEquals(x.Array, x.Offset, y.Array, y.Offset, x.Count) != 0; + } + + /// + /// Comparison of two byte sequences. + /// + /// The runtime of this method does not depend on the contents of the arrays. Using constant time + /// prevents timing attacks that allow an attacker to learn if the arrays have a common prefix. + /// + /// It is important to use such a constant time comparison when verifying MACs. + /// + /// Byte array + /// Offset of byte sequence in the x array + /// Byte array + /// Offset of byte sequence in the y array + /// Lengh of byte sequence + /// True if sequences are equal + public static bool ConstantTimeEquals(byte[] x, int xOffset, byte[] y, int yOffset, int length) + { + return InternalConstantTimeEquals(x, xOffset, y, yOffset, length) != 0; + } + + private static uint InternalConstantTimeEquals(byte[] x, int xOffset, byte[] y, int yOffset, int length) + { + int differentbits = 0; + for (int i = 0; i < length; i++) + differentbits |= x[xOffset + i] ^ y[yOffset + i]; + return (1 & (unchecked((uint)differentbits - 1) >> 8)); + } + + /// + /// Overwrites the contents of the array, wiping the previous content. + /// + /// Byte array + public static void Wipe(byte[] data) + { + InternalWipe(data, 0, data.Length); + } + + /// + /// Overwrites the contents of the array, wiping the previous content. + /// + /// Byte array + /// Index of byte sequence + /// Length of byte sequence + public static void Wipe(byte[] data, int offset, int length) + { + InternalWipe(data, offset, length); + } + + /// + /// Overwrites the contents of the array segment, wiping the previous content. + /// + /// Byte array segment + public static void Wipe(ArraySegment data) + { + InternalWipe(data.Array, data.Offset, data.Count); + } + + // Secure wiping is hard + // * the GC can move around and copy memory + // Perhaps this can be avoided by using unmanaged memory or by fixing the position of the array in memory + // * Swap files and error dumps can contain secret information + // It seems possible to lock memory in RAM, no idea about error dumps + // * Compiler could optimize out the wiping if it knows that data won't be read back + // I hope this is enough, suppressing inlining + // but perhaps `RtlSecureZeroMemory` is needed + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void InternalWipe(byte[] data, int offset, int count) + { + Array.Clear(data, offset, count); + } + + // shallow wipe of structs + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void InternalWipe(ref T data) + where T : struct + { + data = default(T); + } + + /// + /// Constant-time conversion of the bytes array to an upper-case hex string. + /// Please see http://stackoverflow.com/a/14333437/445517 for the detailed explanation + /// + /// Byte array + /// Hex representation of byte array + public static string ToHexStringUpper(byte[] data) + { + if (data == null) + return null; + char[] c = new char[data.Length * 2]; + int b; + for (int i = 0; i < data.Length; i++) + { + b = data[i] >> 4; + c[i * 2] = (char)(55 + b + (((b - 10) >> 31) & -7)); + b = data[i] & 0xF; + c[i * 2 + 1] = (char)(55 + b + (((b - 10) >> 31) & -7)); + } + return new string(c); + } + + /// + /// Constant-time conversion of the bytes array to an lower-case hex string. + /// Please see http://stackoverflow.com/a/14333437/445517 for the detailed explanation. + /// + /// Byte array + /// Hex representation of byte array + public static string ToHexStringLower(byte[] data) + { + if (data == null) + return null; + char[] c = new char[data.Length * 2]; + int b; + for (int i = 0; i < data.Length; i++) + { + b = data[i] >> 4; + c[i * 2] = (char)(87 + b + (((b - 10) >> 31) & -39)); + b = data[i] & 0xF; + c[i * 2 + 1] = (char)(87 + b + (((b - 10) >> 31) & -39)); + } + return new string(c); + } + + /// + /// Converts the hex string to bytes. Case insensitive. + /// + /// Hex encoded byte sequence + /// Byte array + public static byte[] FromHexString(string hexString) + { + if (hexString == null) + return null; + if (hexString.Length % 2 != 0) + throw new FormatException("The hex string is invalid because it has an odd length"); + var result = new byte[hexString.Length / 2]; + for (int i = 0; i < result.Length; i++) + result[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); + return result; + } + + /// + /// Encodes the bytes with the Base64 encoding. + /// More compact than hex, but it is case-sensitive and uses the special characters `+`, `/` and `=`. + /// + /// Byte array + /// Base 64 encoded data + public static string ToBase64String(byte[] data) + { + if (data == null) + return null; + return Convert.ToBase64String(data); + } + + /// + /// Decodes a Base64 encoded string back to bytes. + /// + /// Base 64 encoded data + /// Byte array + public static byte[] FromBase64String(string base64String) + { + if (base64String == null) + return null; + return Convert.FromBase64String(base64String); + } + + private const string strDigits = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + + /// + /// Encode a byte sequence as a base58-encoded string + /// + /// Byte sequence + /// Encoding result + public static string Base58Encode(byte[] input) + { + // Decode byte[] to BigInteger + BigInteger intData = 0; + for (int i = 0; i < input.Length; i++) + { + intData = intData * 256 + input[i]; + } + + // Encode BigInteger to Base58 string + string result = ""; + while (intData > 0) + { + int remainder = (int)(intData % 58); + intData /= 58; + result = strDigits[remainder] + result; + } + + // Append `1` for each leading 0 byte + for (int i = 0; i < input.Length && input[i] == 0; i++) + { + result = '1' + result; + } + return result; + } + + /// + /// // Decode a base58-encoded string into byte array + /// + /// Base58 data string + /// Byte array + public static byte[] Base58Decode(string input) + { + // Decode Base58 string to BigInteger + BigInteger intData = 0; + for (int i = 0; i < input.Length; i++) + { + int digit = strDigits.IndexOf(input[i]); //Slow + if (digit < 0) + throw new FormatException(string.Format("Invalid Base58 character `{0}` at position {1}", input[i], i)); + intData = intData * 58 + digit; + } + + // Encode BigInteger to byte[] + // Leading zero bytes get encoded as leading `1` characters + int leadingZeroCount = input.TakeWhile(c => c == '1').Count(); + var leadingZeros = Enumerable.Repeat((byte)0, leadingZeroCount); + var bytesWithoutLeadingZeros = + intData.ToByteArray() + .Reverse()// to big endian + .SkipWhile(b => b == 0);//strip sign byte + var result = leadingZeros.Concat(bytesWithoutLeadingZeros).ToArray(); + return result; + } + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519.cs new file mode 100644 index 000000000..109620efd --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.Net.ED25519 +{ + internal static class Ed25519 + { + /// + /// Public Keys are 32 byte values. All possible values of this size a valid. + /// + public const int PublicKeySize = 32; + /// + /// Signatures are 64 byte values + /// + public const int SignatureSize = 64; + /// + /// Private key seeds are 32 byte arbitrary values. This is the form that should be generated and stored. + /// + public const int PrivateKeySeedSize = 32; + /// + /// A 64 byte expanded form of private key. This form is used internally to improve performance + /// + public const int ExpandedPrivateKeySize = 32 * 2; + + /// + /// Verify Ed25519 signature + /// + /// Signature bytes + /// Message + /// Public key + /// True if signature is valid, false if it's not + public static bool Verify(ArraySegment signature, ArraySegment message, ArraySegment publicKey) + { + if (signature.Count != SignatureSize) + throw new ArgumentException($"Sizeof signature doesnt match defined size of {SignatureSize}"); + + if (publicKey.Count != PublicKeySize) + throw new ArgumentException($"Sizeof public key doesnt match defined size of {PublicKeySize}"); + + return Ed25519Operations.crypto_sign_verify(signature.Array, signature.Offset, message.Array, message.Offset, message.Count, publicKey.Array, publicKey.Offset); + } + + /// + /// Verify Ed25519 signature + /// + /// Signature bytes + /// Message + /// Public key + /// True if signature is valid, false if it's not + public static bool Verify(byte[] signature, byte[] message, byte[] publicKey) + { + Preconditions.NotNull(signature, nameof(signature)); + Preconditions.NotNull(message, nameof(message)); + Preconditions.NotNull(publicKey, nameof(publicKey)); + if (signature.Length != SignatureSize) + throw new ArgumentException($"Sizeof signature doesnt match defined size of {SignatureSize}"); + + if (publicKey.Length != PublicKeySize) + throw new ArgumentException($"Sizeof public key doesnt match defined size of {PublicKeySize}"); + + return Ed25519Operations.crypto_sign_verify(signature, 0, message, 0, message.Length, publicKey, 0); + } + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Operations.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Operations.cs new file mode 100644 index 000000000..4d5ece1e5 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Operations.cs @@ -0,0 +1,45 @@ +using Discord.Net.ED25519.Ed25519Ref10; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.Net.ED25519 +{ + internal class Ed25519Operations + { + public static bool crypto_sign_verify( + byte[] sig, int sigoffset, + byte[] m, int moffset, int mlen, + byte[] pk, int pkoffset) + { + byte[] h; + byte[] checkr = new byte[32]; + GroupElementP3 A; + GroupElementP2 R; + + if ((sig[sigoffset + 63] & 224) != 0) + return false; + if (GroupOperations.ge_frombytes_negate_vartime(out A, pk, pkoffset) != 0) + return false; + + var hasher = new Sha512(); + hasher.Update(sig, sigoffset, 32); + hasher.Update(pk, pkoffset, 32); + hasher.Update(m, moffset, mlen); + h = hasher.Finalize(); + + ScalarOperations.sc_reduce(h); + + var sm32 = new byte[32]; + Array.Copy(sig, sigoffset + 32, sm32, 0, 32); + GroupOperations.ge_double_scalarmult_vartime(out R, h, ref A, sm32); + GroupOperations.ge_tobytes(checkr, 0, ref R); + var result = CryptoBytes.ConstantTimeEquals(checkr, 0, sig, sigoffset, 32); + CryptoBytes.Wipe(h); + CryptoBytes.Wipe(checkr); + return result; + } + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/FieldElement.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/FieldElement.cs new file mode 100644 index 000000000..d612ff5be --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/FieldElement.cs @@ -0,0 +1,23 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal struct FieldElement + { + internal int x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; + + internal FieldElement(params int[] elements) + { + x0 = elements[0]; + x1 = elements[1]; + x2 = elements[2]; + x3 = elements[3]; + x4 = elements[4]; + x5 = elements[5]; + x6 = elements[6]; + x7 = elements[7]; + x8 = elements[8]; + x9 = elements[9]; + } + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/GroupElement.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/GroupElement.cs new file mode 100644 index 000000000..d54b5ada7 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/GroupElement.cs @@ -0,0 +1,63 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + /* + ge means group element. + + Here the group is the set of pairs (x,y) of field elements (see fe.h) + satisfying -x^2 + y^2 = 1 + d x^2y^2 + where d = -121665/121666. + + Representations: + ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z + ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT + ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T + ge_precomp (Duif): (y+x,y-x,2dxy) + */ + + internal struct GroupElementP2 + { + public FieldElement X; + public FieldElement Y; + public FieldElement Z; + } ; + + internal struct GroupElementP3 + { + public FieldElement X; + public FieldElement Y; + public FieldElement Z; + public FieldElement T; + } ; + + internal struct GroupElementP1P1 + { + public FieldElement X; + public FieldElement Y; + public FieldElement Z; + public FieldElement T; + } ; + + internal struct GroupElementPreComp + { + public FieldElement yplusx; + public FieldElement yminusx; + public FieldElement xy2d; + + public GroupElementPreComp(FieldElement yplusx, FieldElement yminusx, FieldElement xy2d) + { + this.yplusx = yplusx; + this.yminusx = yminusx; + this.xy2d = xy2d; + } + } ; + + internal struct GroupElementCached + { + public FieldElement YplusX; + public FieldElement YminusX; + public FieldElement Z; + public FieldElement T2d; + } ; +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/base.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/base.cs new file mode 100644 index 000000000..2a25504c9 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/base.cs @@ -0,0 +1,1355 @@ +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class LookupTables + { + /* base[i][j] = (j+1)*256^i*B */ + //32*8 + internal static GroupElementPreComp[][] Base = new GroupElementPreComp[][] + { + new[]{ + new GroupElementPreComp( + new FieldElement( 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 ), + new FieldElement( -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 ), + new FieldElement( -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 ) + ), + new GroupElementPreComp( + new FieldElement( -12815894,-12976347,-21581243,11784320,-25355658,-2750717,-11717903,-3814571,-358445,-10211303 ), + new FieldElement( -21703237,6903825,27185491,6451973,-29577724,-9554005,-15616551,11189268,-26829678,-5319081 ), + new FieldElement( 26966642,11152617,32442495,15396054,14353839,-12752335,-3128826,-9541118,-15472047,-4166697 ) + ), + new GroupElementPreComp( + new FieldElement( 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 ), + new FieldElement( 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 ), + new FieldElement( 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 ) + ), + new GroupElementPreComp( + new FieldElement( -17036878,13921892,10945806,-6033431,27105052,-16084379,-28926210,15006023,3284568,-6276540 ), + new FieldElement( 23599295,-8306047,-11193664,-7687416,13236774,10506355,7464579,9656445,13059162,10374397 ), + new FieldElement( 7798556,16710257,3033922,2874086,28997861,2835604,32406664,-3839045,-641708,-101325 ) + ), + new GroupElementPreComp( + new FieldElement( 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 ), + new FieldElement( 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 ), + new FieldElement( 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 ) + ), + new GroupElementPreComp( + new FieldElement( -15371964,-12862754,32573250,4720197,-26436522,5875511,-19188627,-15224819,-9818940,-12085777 ), + new FieldElement( -8549212,109983,15149363,2178705,22900618,4543417,3044240,-15689887,1762328,14866737 ), + new FieldElement( -18199695,-15951423,-10473290,1707278,-17185920,3916101,-28236412,3959421,27914454,4383652 ) + ), + new GroupElementPreComp( + new FieldElement( 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 ), + new FieldElement( -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 ), + new FieldElement( 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 ) + ), + new GroupElementPreComp( + new FieldElement( 14499471,-2729599,-33191113,-4254652,28494862,14271267,30290735,10876454,-33154098,2381726 ), + new FieldElement( -7195431,-2655363,-14730155,462251,-27724326,3941372,-6236617,3696005,-32300832,15351955 ), + new FieldElement( 27431194,8222322,16448760,-3907995,-18707002,11938355,-32961401,-2970515,29551813,10109425 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -13657040,-13155431,-31283750,11777098,21447386,6519384,-2378284,-1627556,10092783,-4764171 ), + new FieldElement( 27939166,14210322,4677035,16277044,-22964462,-12398139,-32508754,12005538,-17810127,12803510 ), + new FieldElement( 17228999,-15661624,-1233527,300140,-1224870,-11714777,30364213,-9038194,18016357,4397660 ) + ), + new GroupElementPreComp( + new FieldElement( -10958843,-7690207,4776341,-14954238,27850028,-15602212,-26619106,14544525,-17477504,982639 ), + new FieldElement( 29253598,15796703,-2863982,-9908884,10057023,3163536,7332899,-4120128,-21047696,9934963 ), + new FieldElement( 5793303,16271923,-24131614,-10116404,29188560,1206517,-14747930,4559895,-30123922,-10897950 ) + ), + new GroupElementPreComp( + new FieldElement( -27643952,-11493006,16282657,-11036493,28414021,-15012264,24191034,4541697,-13338309,5500568 ), + new FieldElement( 12650548,-1497113,9052871,11355358,-17680037,-8400164,-17430592,12264343,10874051,13524335 ), + new FieldElement( 25556948,-3045990,714651,2510400,23394682,-10415330,33119038,5080568,-22528059,5376628 ) + ), + new GroupElementPreComp( + new FieldElement( -26088264,-4011052,-17013699,-3537628,-6726793,1920897,-22321305,-9447443,4535768,1569007 ), + new FieldElement( -2255422,14606630,-21692440,-8039818,28430649,8775819,-30494562,3044290,31848280,12543772 ), + new FieldElement( -22028579,2943893,-31857513,6777306,13784462,-4292203,-27377195,-2062731,7718482,14474653 ) + ), + new GroupElementPreComp( + new FieldElement( 2385315,2454213,-22631320,46603,-4437935,-15680415,656965,-7236665,24316168,-5253567 ), + new FieldElement( 13741529,10911568,-33233417,-8603737,-20177830,-1033297,33040651,-13424532,-20729456,8321686 ), + new FieldElement( 21060490,-2212744,15712757,-4336099,1639040,10656336,23845965,-11874838,-9984458,608372 ) + ), + new GroupElementPreComp( + new FieldElement( -13672732,-15087586,-10889693,-7557059,-6036909,11305547,1123968,-6780577,27229399,23887 ), + new FieldElement( -23244140,-294205,-11744728,14712571,-29465699,-2029617,12797024,-6440308,-1633405,16678954 ), + new FieldElement( -29500620,4770662,-16054387,14001338,7830047,9564805,-1508144,-4795045,-17169265,4904953 ) + ), + new GroupElementPreComp( + new FieldElement( 24059557,14617003,19037157,-15039908,19766093,-14906429,5169211,16191880,2128236,-4326833 ), + new FieldElement( -16981152,4124966,-8540610,-10653797,30336522,-14105247,-29806336,916033,-6882542,-2986532 ), + new FieldElement( -22630907,12419372,-7134229,-7473371,-16478904,16739175,285431,2763829,15736322,4143876 ) + ), + new GroupElementPreComp( + new FieldElement( 2379352,11839345,-4110402,-5988665,11274298,794957,212801,-14594663,23527084,-16458268 ), + new FieldElement( 33431127,-11130478,-17838966,-15626900,8909499,8376530,-32625340,4087881,-15188911,-14416214 ), + new FieldElement( 1767683,7197987,-13205226,-2022635,-13091350,448826,5799055,4357868,-4774191,-16323038 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 6721966,13833823,-23523388,-1551314,26354293,-11863321,23365147,-3949732,7390890,2759800 ), + new FieldElement( 4409041,2052381,23373853,10530217,7676779,-12885954,21302353,-4264057,1244380,-12919645 ), + new FieldElement( -4421239,7169619,4982368,-2957590,30256825,-2777540,14086413,9208236,15886429,16489664 ) + ), + new GroupElementPreComp( + new FieldElement( 1996075,10375649,14346367,13311202,-6874135,-16438411,-13693198,398369,-30606455,-712933 ), + new FieldElement( -25307465,9795880,-2777414,14878809,-33531835,14780363,13348553,12076947,-30836462,5113182 ), + new FieldElement( -17770784,11797796,31950843,13929123,-25888302,12288344,-30341101,-7336386,13847711,5387222 ) + ), + new GroupElementPreComp( + new FieldElement( -18582163,-3416217,17824843,-2340966,22744343,-10442611,8763061,3617786,-19600662,10370991 ), + new FieldElement( 20246567,-14369378,22358229,-543712,18507283,-10413996,14554437,-8746092,32232924,16763880 ), + new FieldElement( 9648505,10094563,26416693,14745928,-30374318,-6472621,11094161,15689506,3140038,-16510092 ) + ), + new GroupElementPreComp( + new FieldElement( -16160072,5472695,31895588,4744994,8823515,10365685,-27224800,9448613,-28774454,366295 ), + new FieldElement( 19153450,11523972,-11096490,-6503142,-24647631,5420647,28344573,8041113,719605,11671788 ), + new FieldElement( 8678025,2694440,-6808014,2517372,4964326,11152271,-15432916,-15266516,27000813,-10195553 ) + ), + new GroupElementPreComp( + new FieldElement( -15157904,7134312,8639287,-2814877,-7235688,10421742,564065,5336097,6750977,-14521026 ), + new FieldElement( 11836410,-3979488,26297894,16080799,23455045,15735944,1695823,-8819122,8169720,16220347 ), + new FieldElement( -18115838,8653647,17578566,-6092619,-8025777,-16012763,-11144307,-2627664,-5990708,-14166033 ) + ), + new GroupElementPreComp( + new FieldElement( -23308498,-10968312,15213228,-10081214,-30853605,-11050004,27884329,2847284,2655861,1738395 ), + new FieldElement( -27537433,-14253021,-25336301,-8002780,-9370762,8129821,21651608,-3239336,-19087449,-11005278 ), + new FieldElement( 1533110,3437855,23735889,459276,29970501,11335377,26030092,5821408,10478196,8544890 ) + ), + new GroupElementPreComp( + new FieldElement( 32173121,-16129311,24896207,3921497,22579056,-3410854,19270449,12217473,17789017,-3395995 ), + new FieldElement( -30552961,-2228401,-15578829,-10147201,13243889,517024,15479401,-3853233,30460520,1052596 ), + new FieldElement( -11614875,13323618,32618793,8175907,-15230173,12596687,27491595,-4612359,3179268,-9478891 ) + ), + new GroupElementPreComp( + new FieldElement( 31947069,-14366651,-4640583,-15339921,-15125977,-6039709,-14756777,-16411740,19072640,-9511060 ), + new FieldElement( 11685058,11822410,3158003,-13952594,33402194,-4165066,5977896,-5215017,473099,5040608 ), + new FieldElement( -20290863,8198642,-27410132,11602123,1290375,-2799760,28326862,1721092,-19558642,-3131606 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 7881532,10687937,7578723,7738378,-18951012,-2553952,21820786,8076149,-27868496,11538389 ), + new FieldElement( -19935666,3899861,18283497,-6801568,-15728660,-11249211,8754525,7446702,-5676054,5797016 ), + new FieldElement( -11295600,-3793569,-15782110,-7964573,12708869,-8456199,2014099,-9050574,-2369172,-5877341 ) + ), + new GroupElementPreComp( + new FieldElement( -22472376,-11568741,-27682020,1146375,18956691,16640559,1192730,-3714199,15123619,10811505 ), + new FieldElement( 14352098,-3419715,-18942044,10822655,32750596,4699007,-70363,15776356,-28886779,-11974553 ), + new FieldElement( -28241164,-8072475,-4978962,-5315317,29416931,1847569,-20654173,-16484855,4714547,-9600655 ) + ), + new GroupElementPreComp( + new FieldElement( 15200332,8368572,19679101,15970074,-31872674,1959451,24611599,-4543832,-11745876,12340220 ), + new FieldElement( 12876937,-10480056,33134381,6590940,-6307776,14872440,9613953,8241152,15370987,9608631 ), + new FieldElement( -4143277,-12014408,8446281,-391603,4407738,13629032,-7724868,15866074,-28210621,-8814099 ) + ), + new GroupElementPreComp( + new FieldElement( 26660628,-15677655,8393734,358047,-7401291,992988,-23904233,858697,20571223,8420556 ), + new FieldElement( 14620715,13067227,-15447274,8264467,14106269,15080814,33531827,12516406,-21574435,-12476749 ), + new FieldElement( 236881,10476226,57258,-14677024,6472998,2466984,17258519,7256740,8791136,15069930 ) + ), + new GroupElementPreComp( + new FieldElement( 1276410,-9371918,22949635,-16322807,-23493039,-5702186,14711875,4874229,-30663140,-2331391 ), + new FieldElement( 5855666,4990204,-13711848,7294284,-7804282,1924647,-1423175,-7912378,-33069337,9234253 ), + new FieldElement( 20590503,-9018988,31529744,-7352666,-2706834,10650548,31559055,-11609587,18979186,13396066 ) + ), + new GroupElementPreComp( + new FieldElement( 24474287,4968103,22267082,4407354,24063882,-8325180,-18816887,13594782,33514650,7021958 ), + new FieldElement( -11566906,-6565505,-21365085,15928892,-26158305,4315421,-25948728,-3916677,-21480480,12868082 ), + new FieldElement( -28635013,13504661,19988037,-2132761,21078225,6443208,-21446107,2244500,-12455797,-8089383 ) + ), + new GroupElementPreComp( + new FieldElement( -30595528,13793479,-5852820,319136,-25723172,-6263899,33086546,8957937,-15233648,5540521 ), + new FieldElement( -11630176,-11503902,-8119500,-7643073,2620056,1022908,-23710744,-1568984,-16128528,-14962807 ), + new FieldElement( 23152971,775386,27395463,14006635,-9701118,4649512,1689819,892185,-11513277,-15205948 ) + ), + new GroupElementPreComp( + new FieldElement( 9770129,9586738,26496094,4324120,1556511,-3550024,27453819,4763127,-19179614,5867134 ), + new FieldElement( -32765025,1927590,31726409,-4753295,23962434,-16019500,27846559,5931263,-29749703,-16108455 ), + new FieldElement( 27461885,-2977536,22380810,1815854,-23033753,-3031938,7283490,-15148073,-19526700,7734629 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -8010264,-9590817,-11120403,6196038,29344158,-13430885,7585295,-3176626,18549497,15302069 ), + new FieldElement( -32658337,-6171222,-7672793,-11051681,6258878,13504381,10458790,-6418461,-8872242,8424746 ), + new FieldElement( 24687205,8613276,-30667046,-3233545,1863892,-1830544,19206234,7134917,-11284482,-828919 ) + ), + new GroupElementPreComp( + new FieldElement( 11334899,-9218022,8025293,12707519,17523892,-10476071,10243738,-14685461,-5066034,16498837 ), + new FieldElement( 8911542,6887158,-9584260,-6958590,11145641,-9543680,17303925,-14124238,6536641,10543906 ), + new FieldElement( -28946384,15479763,-17466835,568876,-1497683,11223454,-2669190,-16625574,-27235709,8876771 ) + ), + new GroupElementPreComp( + new FieldElement( -25742899,-12566864,-15649966,-846607,-33026686,-796288,-33481822,15824474,-604426,-9039817 ), + new FieldElement( 10330056,70051,7957388,-9002667,9764902,15609756,27698697,-4890037,1657394,3084098 ), + new FieldElement( 10477963,-7470260,12119566,-13250805,29016247,-5365589,31280319,14396151,-30233575,15272409 ) + ), + new GroupElementPreComp( + new FieldElement( -12288309,3169463,28813183,16658753,25116432,-5630466,-25173957,-12636138,-25014757,1950504 ), + new FieldElement( -26180358,9489187,11053416,-14746161,-31053720,5825630,-8384306,-8767532,15341279,8373727 ), + new FieldElement( 28685821,7759505,-14378516,-12002860,-31971820,4079242,298136,-10232602,-2878207,15190420 ) + ), + new GroupElementPreComp( + new FieldElement( -32932876,13806336,-14337485,-15794431,-24004620,10940928,8669718,2742393,-26033313,-6875003 ), + new FieldElement( -1580388,-11729417,-25979658,-11445023,-17411874,-10912854,9291594,-16247779,-12154742,6048605 ), + new FieldElement( -30305315,14843444,1539301,11864366,20201677,1900163,13934231,5128323,11213262,9168384 ) + ), + new GroupElementPreComp( + new FieldElement( -26280513,11007847,19408960,-940758,-18592965,-4328580,-5088060,-11105150,20470157,-16398701 ), + new FieldElement( -23136053,9282192,14855179,-15390078,-7362815,-14408560,-22783952,14461608,14042978,5230683 ), + new FieldElement( 29969567,-2741594,-16711867,-8552442,9175486,-2468974,21556951,3506042,-5933891,-12449708 ) + ), + new GroupElementPreComp( + new FieldElement( -3144746,8744661,19704003,4581278,-20430686,6830683,-21284170,8971513,-28539189,15326563 ), + new FieldElement( -19464629,10110288,-17262528,-3503892,-23500387,1355669,-15523050,15300988,-20514118,9168260 ), + new FieldElement( -5353335,4488613,-23803248,16314347,7780487,-15638939,-28948358,9601605,33087103,-9011387 ) + ), + new GroupElementPreComp( + new FieldElement( -19443170,-15512900,-20797467,-12445323,-29824447,10229461,-27444329,-15000531,-5996870,15664672 ), + new FieldElement( 23294591,-16632613,-22650781,-8470978,27844204,11461195,13099750,-2460356,18151676,13417686 ), + new FieldElement( -24722913,-4176517,-31150679,5988919,-26858785,6685065,1661597,-12551441,15271676,-15452665 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 11433042,-13228665,8239631,-5279517,-1985436,-725718,-18698764,2167544,-6921301,-13440182 ), + new FieldElement( -31436171,15575146,30436815,12192228,-22463353,9395379,-9917708,-8638997,12215110,12028277 ), + new FieldElement( 14098400,6555944,23007258,5757252,-15427832,-12950502,30123440,4617780,-16900089,-655628 ) + ), + new GroupElementPreComp( + new FieldElement( -4026201,-15240835,11893168,13718664,-14809462,1847385,-15819999,10154009,23973261,-12684474 ), + new FieldElement( -26531820,-3695990,-1908898,2534301,-31870557,-16550355,18341390,-11419951,32013174,-10103539 ), + new FieldElement( -25479301,10876443,-11771086,-14625140,-12369567,1838104,21911214,6354752,4425632,-837822 ) + ), + new GroupElementPreComp( + new FieldElement( -10433389,-14612966,22229858,-3091047,-13191166,776729,-17415375,-12020462,4725005,14044970 ), + new FieldElement( 19268650,-7304421,1555349,8692754,-21474059,-9910664,6347390,-1411784,-19522291,-16109756 ), + new FieldElement( -24864089,12986008,-10898878,-5558584,-11312371,-148526,19541418,8180106,9282262,10282508 ) + ), + new GroupElementPreComp( + new FieldElement( -26205082,4428547,-8661196,-13194263,4098402,-14165257,15522535,8372215,5542595,-10702683 ), + new FieldElement( -10562541,14895633,26814552,-16673850,-17480754,-2489360,-2781891,6993761,-18093885,10114655 ), + new FieldElement( -20107055,-929418,31422704,10427861,-7110749,6150669,-29091755,-11529146,25953725,-106158 ) + ), + new GroupElementPreComp( + new FieldElement( -4234397,-8039292,-9119125,3046000,2101609,-12607294,19390020,6094296,-3315279,12831125 ), + new FieldElement( -15998678,7578152,5310217,14408357,-33548620,-224739,31575954,6326196,7381791,-2421839 ), + new FieldElement( -20902779,3296811,24736065,-16328389,18374254,7318640,6295303,8082724,-15362489,12339664 ) + ), + new GroupElementPreComp( + new FieldElement( 27724736,2291157,6088201,-14184798,1792727,5857634,13848414,15768922,25091167,14856294 ), + new FieldElement( -18866652,8331043,24373479,8541013,-701998,-9269457,12927300,-12695493,-22182473,-9012899 ), + new FieldElement( -11423429,-5421590,11632845,3405020,30536730,-11674039,-27260765,13866390,30146206,9142070 ) + ), + new GroupElementPreComp( + new FieldElement( 3924129,-15307516,-13817122,-10054960,12291820,-668366,-27702774,9326384,-8237858,4171294 ), + new FieldElement( -15921940,16037937,6713787,16606682,-21612135,2790944,26396185,3731949,345228,-5462949 ), + new FieldElement( -21327538,13448259,25284571,1143661,20614966,-8849387,2031539,-12391231,-16253183,-13582083 ) + ), + new GroupElementPreComp( + new FieldElement( 31016211,-16722429,26371392,-14451233,-5027349,14854137,17477601,3842657,28012650,-16405420 ), + new FieldElement( -5075835,9368966,-8562079,-4600902,-15249953,6970560,-9189873,16292057,-8867157,3507940 ), + new FieldElement( 29439664,3537914,23333589,6997794,-17555561,-11018068,-15209202,-15051267,-9164929,6580396 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -12185861,-7679788,16438269,10826160,-8696817,-6235611,17860444,-9273846,-2095802,9304567 ), + new FieldElement( 20714564,-4336911,29088195,7406487,11426967,-5095705,14792667,-14608617,5289421,-477127 ), + new FieldElement( -16665533,-10650790,-6160345,-13305760,9192020,-1802462,17271490,12349094,26939669,-3752294 ) + ), + new GroupElementPreComp( + new FieldElement( -12889898,9373458,31595848,16374215,21471720,13221525,-27283495,-12348559,-3698806,117887 ), + new FieldElement( 22263325,-6560050,3984570,-11174646,-15114008,-566785,28311253,5358056,-23319780,541964 ), + new FieldElement( 16259219,3261970,2309254,-15534474,-16885711,-4581916,24134070,-16705829,-13337066,-13552195 ) + ), + new GroupElementPreComp( + new FieldElement( 9378160,-13140186,-22845982,-12745264,28198281,-7244098,-2399684,-717351,690426,14876244 ), + new FieldElement( 24977353,-314384,-8223969,-13465086,28432343,-1176353,-13068804,-12297348,-22380984,6618999 ), + new FieldElement( -1538174,11685646,12944378,13682314,-24389511,-14413193,8044829,-13817328,32239829,-5652762 ) + ), + new GroupElementPreComp( + new FieldElement( -18603066,4762990,-926250,8885304,-28412480,-3187315,9781647,-10350059,32779359,5095274 ), + new FieldElement( -33008130,-5214506,-32264887,-3685216,9460461,-9327423,-24601656,14506724,21639561,-2630236 ), + new FieldElement( -16400943,-13112215,25239338,15531969,3987758,-4499318,-1289502,-6863535,17874574,558605 ) + ), + new GroupElementPreComp( + new FieldElement( -13600129,10240081,9171883,16131053,-20869254,9599700,33499487,5080151,2085892,5119761 ), + new FieldElement( -22205145,-2519528,-16381601,414691,-25019550,2170430,30634760,-8363614,-31999993,-5759884 ), + new FieldElement( -6845704,15791202,8550074,-1312654,29928809,-12092256,27534430,-7192145,-22351378,12961482 ) + ), + new GroupElementPreComp( + new FieldElement( -24492060,-9570771,10368194,11582341,-23397293,-2245287,16533930,8206996,-30194652,-5159638 ), + new FieldElement( -11121496,-3382234,2307366,6362031,-135455,8868177,-16835630,7031275,7589640,8945490 ), + new FieldElement( -32152748,8917967,6661220,-11677616,-1192060,-15793393,7251489,-11182180,24099109,-14456170 ) + ), + new GroupElementPreComp( + new FieldElement( 5019558,-7907470,4244127,-14714356,-26933272,6453165,-19118182,-13289025,-6231896,-10280736 ), + new FieldElement( 10853594,10721687,26480089,5861829,-22995819,1972175,-1866647,-10557898,-3363451,-6441124 ), + new FieldElement( -17002408,5906790,221599,-6563147,7828208,-13248918,24362661,-2008168,-13866408,7421392 ) + ), + new GroupElementPreComp( + new FieldElement( 8139927,-6546497,32257646,-5890546,30375719,1886181,-21175108,15441252,28826358,-4123029 ), + new FieldElement( 6267086,9695052,7709135,-16603597,-32869068,-1886135,14795160,-7840124,13746021,-1742048 ), + new FieldElement( 28584902,7787108,-6732942,-15050729,22846041,-7571236,-3181936,-363524,4771362,-8419958 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 24949256,6376279,-27466481,-8174608,-18646154,-9930606,33543569,-12141695,3569627,11342593 ), + new FieldElement( 26514989,4740088,27912651,3697550,19331575,-11472339,6809886,4608608,7325975,-14801071 ), + new FieldElement( -11618399,-14554430,-24321212,7655128,-1369274,5214312,-27400540,10258390,-17646694,-8186692 ) + ), + new GroupElementPreComp( + new FieldElement( 11431204,15823007,26570245,14329124,18029990,4796082,-31446179,15580664,9280358,-3973687 ), + new FieldElement( -160783,-10326257,-22855316,-4304997,-20861367,-13621002,-32810901,-11181622,-15545091,4387441 ), + new FieldElement( -20799378,12194512,3937617,-5805892,-27154820,9340370,-24513992,8548137,20617071,-7482001 ) + ), + new GroupElementPreComp( + new FieldElement( -938825,-3930586,-8714311,16124718,24603125,-6225393,-13775352,-11875822,24345683,10325460 ), + new FieldElement( -19855277,-1568885,-22202708,8714034,14007766,6928528,16318175,-1010689,4766743,3552007 ), + new FieldElement( -21751364,-16730916,1351763,-803421,-4009670,3950935,3217514,14481909,10988822,-3994762 ) + ), + new GroupElementPreComp( + new FieldElement( 15564307,-14311570,3101243,5684148,30446780,-8051356,12677127,-6505343,-8295852,13296005 ), + new FieldElement( -9442290,6624296,-30298964,-11913677,-4670981,-2057379,31521204,9614054,-30000824,12074674 ), + new FieldElement( 4771191,-135239,14290749,-13089852,27992298,14998318,-1413936,-1556716,29832613,-16391035 ) + ), + new GroupElementPreComp( + new FieldElement( 7064884,-7541174,-19161962,-5067537,-18891269,-2912736,25825242,5293297,-27122660,13101590 ), + new FieldElement( -2298563,2439670,-7466610,1719965,-27267541,-16328445,32512469,-5317593,-30356070,-4190957 ), + new FieldElement( -30006540,10162316,-33180176,3981723,-16482138,-13070044,14413974,9515896,19568978,9628812 ) + ), + new GroupElementPreComp( + new FieldElement( 33053803,199357,15894591,1583059,27380243,-4580435,-17838894,-6106839,-6291786,3437740 ), + new FieldElement( -18978877,3884493,19469877,12726490,15913552,13614290,-22961733,70104,7463304,4176122 ), + new FieldElement( -27124001,10659917,11482427,-16070381,12771467,-6635117,-32719404,-5322751,24216882,5944158 ) + ), + new GroupElementPreComp( + new FieldElement( 8894125,7450974,-2664149,-9765752,-28080517,-12389115,19345746,14680796,11632993,5847885 ), + new FieldElement( 26942781,-2315317,9129564,-4906607,26024105,11769399,-11518837,6367194,-9727230,4782140 ), + new FieldElement( 19916461,-4828410,-22910704,-11414391,25606324,-5972441,33253853,8220911,6358847,-1873857 ) + ), + new GroupElementPreComp( + new FieldElement( 801428,-2081702,16569428,11065167,29875704,96627,7908388,-4480480,-13538503,1387155 ), + new FieldElement( 19646058,5720633,-11416706,12814209,11607948,12749789,14147075,15156355,-21866831,11835260 ), + new FieldElement( 19299512,1155910,28703737,14890794,2925026,7269399,26121523,15467869,-26560550,5052483 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -3017432,10058206,1980837,3964243,22160966,12322533,-6431123,-12618185,12228557,-7003677 ), + new FieldElement( 32944382,14922211,-22844894,5188528,21913450,-8719943,4001465,13238564,-6114803,8653815 ), + new FieldElement( 22865569,-4652735,27603668,-12545395,14348958,8234005,24808405,5719875,28483275,2841751 ) + ), + new GroupElementPreComp( + new FieldElement( -16420968,-1113305,-327719,-12107856,21886282,-15552774,-1887966,-315658,19932058,-12739203 ), + new FieldElement( -11656086,10087521,-8864888,-5536143,-19278573,-3055912,3999228,13239134,-4777469,-13910208 ), + new FieldElement( 1382174,-11694719,17266790,9194690,-13324356,9720081,20403944,11284705,-14013818,3093230 ) + ), + new GroupElementPreComp( + new FieldElement( 16650921,-11037932,-1064178,1570629,-8329746,7352753,-302424,16271225,-24049421,-6691850 ), + new FieldElement( -21911077,-5927941,-4611316,-5560156,-31744103,-10785293,24123614,15193618,-21652117,-16739389 ), + new FieldElement( -9935934,-4289447,-25279823,4372842,2087473,10399484,31870908,14690798,17361620,11864968 ) + ), + new GroupElementPreComp( + new FieldElement( -11307610,6210372,13206574,5806320,-29017692,-13967200,-12331205,-7486601,-25578460,-16240689 ), + new FieldElement( 14668462,-12270235,26039039,15305210,25515617,4542480,10453892,6577524,9145645,-6443880 ), + new FieldElement( 5974874,3053895,-9433049,-10385191,-31865124,3225009,-7972642,3936128,-5652273,-3050304 ) + ), + new GroupElementPreComp( + new FieldElement( 30625386,-4729400,-25555961,-12792866,-20484575,7695099,17097188,-16303496,-27999779,1803632 ), + new FieldElement( -3553091,9865099,-5228566,4272701,-5673832,-16689700,14911344,12196514,-21405489,7047412 ), + new FieldElement( 20093277,9920966,-11138194,-5343857,13161587,12044805,-32856851,4124601,-32343828,-10257566 ) + ), + new GroupElementPreComp( + new FieldElement( -20788824,14084654,-13531713,7842147,19119038,-13822605,4752377,-8714640,-21679658,2288038 ), + new FieldElement( -26819236,-3283715,29965059,3039786,-14473765,2540457,29457502,14625692,-24819617,12570232 ), + new FieldElement( -1063558,-11551823,16920318,12494842,1278292,-5869109,-21159943,-3498680,-11974704,4724943 ) + ), + new GroupElementPreComp( + new FieldElement( 17960970,-11775534,-4140968,-9702530,-8876562,-1410617,-12907383,-8659932,-29576300,1903856 ), + new FieldElement( 23134274,-14279132,-10681997,-1611936,20684485,15770816,-12989750,3190296,26955097,14109738 ), + new FieldElement( 15308788,5320727,-30113809,-14318877,22902008,7767164,29425325,-11277562,31960942,11934971 ) + ), + new GroupElementPreComp( + new FieldElement( -27395711,8435796,4109644,12222639,-24627868,14818669,20638173,4875028,10491392,1379718 ), + new FieldElement( -13159415,9197841,3875503,-8936108,-1383712,-5879801,33518459,16176658,21432314,12180697 ), + new FieldElement( -11787308,11500838,13787581,-13832590,-22430679,10140205,1465425,12689540,-10301319,-13872883 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 5414091,-15386041,-21007664,9643570,12834970,1186149,-2622916,-1342231,26128231,6032912 ), + new FieldElement( -26337395,-13766162,32496025,-13653919,17847801,-12669156,3604025,8316894,-25875034,-10437358 ), + new FieldElement( 3296484,6223048,24680646,-12246460,-23052020,5903205,-8862297,-4639164,12376617,3188849 ) + ), + new GroupElementPreComp( + new FieldElement( 29190488,-14659046,27549113,-1183516,3520066,-10697301,32049515,-7309113,-16109234,-9852307 ), + new FieldElement( -14744486,-9309156,735818,-598978,-20407687,-5057904,25246078,-15795669,18640741,-960977 ), + new FieldElement( -6928835,-16430795,10361374,5642961,4910474,12345252,-31638386,-494430,10530747,1053335 ) + ), + new GroupElementPreComp( + new FieldElement( -29265967,-14186805,-13538216,-12117373,-19457059,-10655384,-31462369,-2948985,24018831,15026644 ), + new FieldElement( -22592535,-3145277,-2289276,5953843,-13440189,9425631,25310643,13003497,-2314791,-15145616 ), + new FieldElement( -27419985,-603321,-8043984,-1669117,-26092265,13987819,-27297622,187899,-23166419,-2531735 ) + ), + new GroupElementPreComp( + new FieldElement( -21744398,-13810475,1844840,5021428,-10434399,-15911473,9716667,16266922,-5070217,726099 ), + new FieldElement( 29370922,-6053998,7334071,-15342259,9385287,2247707,-13661962,-4839461,30007388,-15823341 ), + new FieldElement( -936379,16086691,23751945,-543318,-1167538,-5189036,9137109,730663,9835848,4555336 ) + ), + new GroupElementPreComp( + new FieldElement( -23376435,1410446,-22253753,-12899614,30867635,15826977,17693930,544696,-11985298,12422646 ), + new FieldElement( 31117226,-12215734,-13502838,6561947,-9876867,-12757670,-5118685,-4096706,29120153,13924425 ), + new FieldElement( -17400879,-14233209,19675799,-2734756,-11006962,-5858820,-9383939,-11317700,7240931,-237388 ) + ), + new GroupElementPreComp( + new FieldElement( -31361739,-11346780,-15007447,-5856218,-22453340,-12152771,1222336,4389483,3293637,-15551743 ), + new FieldElement( -16684801,-14444245,11038544,11054958,-13801175,-3338533,-24319580,7733547,12796905,-6335822 ), + new FieldElement( -8759414,-10817836,-25418864,10783769,-30615557,-9746811,-28253339,3647836,3222231,-11160462 ) + ), + new GroupElementPreComp( + new FieldElement( 18606113,1693100,-25448386,-15170272,4112353,10045021,23603893,-2048234,-7550776,2484985 ), + new FieldElement( 9255317,-3131197,-12156162,-1004256,13098013,-9214866,16377220,-2102812,-19802075,-3034702 ), + new FieldElement( -22729289,7496160,-5742199,11329249,19991973,-3347502,-31718148,9936966,-30097688,-10618797 ) + ), + new GroupElementPreComp( + new FieldElement( 21878590,-5001297,4338336,13643897,-3036865,13160960,19708896,5415497,-7360503,-4109293 ), + new FieldElement( 27736861,10103576,12500508,8502413,-3413016,-9633558,10436918,-1550276,-23659143,-8132100 ), + new FieldElement( 19492550,-12104365,-29681976,-852630,-3208171,12403437,30066266,8367329,13243957,8709688 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 12015105,2801261,28198131,10151021,24818120,-4743133,-11194191,-5645734,5150968,7274186 ), + new FieldElement( 2831366,-12492146,1478975,6122054,23825128,-12733586,31097299,6083058,31021603,-9793610 ), + new FieldElement( -2529932,-2229646,445613,10720828,-13849527,-11505937,-23507731,16354465,15067285,-14147707 ) + ), + new GroupElementPreComp( + new FieldElement( 7840942,14037873,-33364863,15934016,-728213,-3642706,21403988,1057586,-19379462,-12403220 ), + new FieldElement( 915865,-16469274,15608285,-8789130,-24357026,6060030,-17371319,8410997,-7220461,16527025 ), + new FieldElement( 32922597,-556987,20336074,-16184568,10903705,-5384487,16957574,52992,23834301,6588044 ) + ), + new GroupElementPreComp( + new FieldElement( 32752030,11232950,3381995,-8714866,22652988,-10744103,17159699,16689107,-20314580,-1305992 ), + new FieldElement( -4689649,9166776,-25710296,-10847306,11576752,12733943,7924251,-2752281,1976123,-7249027 ), + new FieldElement( 21251222,16309901,-2983015,-6783122,30810597,12967303,156041,-3371252,12331345,-8237197 ) + ), + new GroupElementPreComp( + new FieldElement( 8651614,-4477032,-16085636,-4996994,13002507,2950805,29054427,-5106970,10008136,-4667901 ), + new FieldElement( 31486080,15114593,-14261250,12951354,14369431,-7387845,16347321,-13662089,8684155,-10532952 ), + new FieldElement( 19443825,11385320,24468943,-9659068,-23919258,2187569,-26263207,-6086921,31316348,14219878 ) + ), + new GroupElementPreComp( + new FieldElement( -28594490,1193785,32245219,11392485,31092169,15722801,27146014,6992409,29126555,9207390 ), + new FieldElement( 32382935,1110093,18477781,11028262,-27411763,-7548111,-4980517,10843782,-7957600,-14435730 ), + new FieldElement( 2814918,7836403,27519878,-7868156,-20894015,-11553689,-21494559,8550130,28346258,1994730 ) + ), + new GroupElementPreComp( + new FieldElement( -19578299,8085545,-14000519,-3948622,2785838,-16231307,-19516951,7174894,22628102,8115180 ), + new FieldElement( -30405132,955511,-11133838,-15078069,-32447087,-13278079,-25651578,3317160,-9943017,930272 ), + new FieldElement( -15303681,-6833769,28856490,1357446,23421993,1057177,24091212,-1388970,-22765376,-10650715 ) + ), + new GroupElementPreComp( + new FieldElement( -22751231,-5303997,-12907607,-12768866,-15811511,-7797053,-14839018,-16554220,-1867018,8398970 ), + new FieldElement( -31969310,2106403,-4736360,1362501,12813763,16200670,22981545,-6291273,18009408,-15772772 ), + new FieldElement( -17220923,-9545221,-27784654,14166835,29815394,7444469,29551787,-3727419,19288549,1325865 ) + ), + new GroupElementPreComp( + new FieldElement( 15100157,-15835752,-23923978,-1005098,-26450192,15509408,12376730,-3479146,33166107,-8042750 ), + new FieldElement( 20909231,13023121,-9209752,16251778,-5778415,-8094914,12412151,10018715,2213263,-13878373 ), + new FieldElement( 32529814,-11074689,30361439,-16689753,-9135940,1513226,22922121,6382134,-5766928,8371348 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 9923462,11271500,12616794,3544722,-29998368,-1721626,12891687,-8193132,-26442943,10486144 ), + new FieldElement( -22597207,-7012665,8587003,-8257861,4084309,-12970062,361726,2610596,-23921530,-11455195 ), + new FieldElement( 5408411,-1136691,-4969122,10561668,24145918,14240566,31319731,-4235541,19985175,-3436086 ) + ), + new GroupElementPreComp( + new FieldElement( -13994457,16616821,14549246,3341099,32155958,13648976,-17577068,8849297,65030,8370684 ), + new FieldElement( -8320926,-12049626,31204563,5839400,-20627288,-1057277,-19442942,6922164,12743482,-9800518 ), + new FieldElement( -2361371,12678785,28815050,4759974,-23893047,4884717,23783145,11038569,18800704,255233 ) + ), + new GroupElementPreComp( + new FieldElement( -5269658,-1773886,13957886,7990715,23132995,728773,13393847,9066957,19258688,-14753793 ), + new FieldElement( -2936654,-10827535,-10432089,14516793,-3640786,4372541,-31934921,2209390,-1524053,2055794 ), + new FieldElement( 580882,16705327,5468415,-2683018,-30926419,-14696000,-7203346,-8994389,-30021019,7394435 ) + ), + new GroupElementPreComp( + new FieldElement( 23838809,1822728,-15738443,15242727,8318092,-3733104,-21672180,-3492205,-4821741,14799921 ), + new FieldElement( 13345610,9759151,3371034,-16137791,16353039,8577942,31129804,13496856,-9056018,7402518 ), + new FieldElement( 2286874,-4435931,-20042458,-2008336,-13696227,5038122,11006906,-15760352,8205061,1607563 ) + ), + new GroupElementPreComp( + new FieldElement( 14414086,-8002132,3331830,-3208217,22249151,-5594188,18364661,-2906958,30019587,-9029278 ), + new FieldElement( -27688051,1585953,-10775053,931069,-29120221,-11002319,-14410829,12029093,9944378,8024 ), + new FieldElement( 4368715,-3709630,29874200,-15022983,-20230386,-11410704,-16114594,-999085,-8142388,5640030 ) + ), + new GroupElementPreComp( + new FieldElement( 10299610,13746483,11661824,16234854,7630238,5998374,9809887,-16694564,15219798,-14327783 ), + new FieldElement( 27425505,-5719081,3055006,10660664,23458024,595578,-15398605,-1173195,-18342183,9742717 ), + new FieldElement( 6744077,2427284,26042789,2720740,-847906,1118974,32324614,7406442,12420155,1994844 ) + ), + new GroupElementPreComp( + new FieldElement( 14012521,-5024720,-18384453,-9578469,-26485342,-3936439,-13033478,-10909803,24319929,-6446333 ), + new FieldElement( 16412690,-4507367,10772641,15929391,-17068788,-4658621,10555945,-10484049,-30102368,-4739048 ), + new FieldElement( 22397382,-7767684,-9293161,-12792868,17166287,-9755136,-27333065,6199366,21880021,-12250760 ) + ), + new GroupElementPreComp( + new FieldElement( -4283307,5368523,-31117018,8163389,-30323063,3209128,16557151,8890729,8840445,4957760 ), + new FieldElement( -15447727,709327,-6919446,-10870178,-29777922,6522332,-21720181,12130072,-14796503,5005757 ), + new FieldElement( -2114751,-14308128,23019042,15765735,-25269683,6002752,10183197,-13239326,-16395286,-2176112 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -19025756,1632005,13466291,-7995100,-23640451,16573537,-32013908,-3057104,22208662,2000468 ), + new FieldElement( 3065073,-1412761,-25598674,-361432,-17683065,-5703415,-8164212,11248527,-3691214,-7414184 ), + new FieldElement( 10379208,-6045554,8877319,1473647,-29291284,-12507580,16690915,2553332,-3132688,16400289 ) + ), + new GroupElementPreComp( + new FieldElement( 15716668,1254266,-18472690,7446274,-8448918,6344164,-22097271,-7285580,26894937,9132066 ), + new FieldElement( 24158887,12938817,11085297,-8177598,-28063478,-4457083,-30576463,64452,-6817084,-2692882 ), + new FieldElement( 13488534,7794716,22236231,5989356,25426474,-12578208,2350710,-3418511,-4688006,2364226 ) + ), + new GroupElementPreComp( + new FieldElement( 16335052,9132434,25640582,6678888,1725628,8517937,-11807024,-11697457,15445875,-7798101 ), + new FieldElement( 29004207,-7867081,28661402,-640412,-12794003,-7943086,31863255,-4135540,-278050,-15759279 ), + new FieldElement( -6122061,-14866665,-28614905,14569919,-10857999,-3591829,10343412,-6976290,-29828287,-10815811 ) + ), + new GroupElementPreComp( + new FieldElement( 27081650,3463984,14099042,-4517604,1616303,-6205604,29542636,15372179,17293797,960709 ), + new FieldElement( 20263915,11434237,-5765435,11236810,13505955,-10857102,-16111345,6493122,-19384511,7639714 ), + new FieldElement( -2830798,-14839232,25403038,-8215196,-8317012,-16173699,18006287,-16043750,29994677,-15808121 ) + ), + new GroupElementPreComp( + new FieldElement( 9769828,5202651,-24157398,-13631392,-28051003,-11561624,-24613141,-13860782,-31184575,709464 ), + new FieldElement( 12286395,13076066,-21775189,-1176622,-25003198,4057652,-32018128,-8890874,16102007,13205847 ), + new FieldElement( 13733362,5599946,10557076,3195751,-5557991,8536970,-25540170,8525972,10151379,10394400 ) + ), + new GroupElementPreComp( + new FieldElement( 4024660,-16137551,22436262,12276534,-9099015,-2686099,19698229,11743039,-33302334,8934414 ), + new FieldElement( -15879800,-4525240,-8580747,-2934061,14634845,-698278,-9449077,3137094,-11536886,11721158 ), + new FieldElement( 17555939,-5013938,8268606,2331751,-22738815,9761013,9319229,8835153,-9205489,-1280045 ) + ), + new GroupElementPreComp( + new FieldElement( -461409,-7830014,20614118,16688288,-7514766,-4807119,22300304,505429,6108462,-6183415 ), + new FieldElement( -5070281,12367917,-30663534,3234473,32617080,-8422642,29880583,-13483331,-26898490,-7867459 ), + new FieldElement( -31975283,5726539,26934134,10237677,-3173717,-605053,24199304,3795095,7592688,-14992079 ) + ), + new GroupElementPreComp( + new FieldElement( 21594432,-14964228,17466408,-4077222,32537084,2739898,6407723,12018833,-28256052,4298412 ), + new FieldElement( -20650503,-11961496,-27236275,570498,3767144,-1717540,13891942,-1569194,13717174,10805743 ), + new FieldElement( -14676630,-15644296,15287174,11927123,24177847,-8175568,-796431,14860609,-26938930,-5863836 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 12962541,5311799,-10060768,11658280,18855286,-7954201,13286263,-12808704,-4381056,9882022 ), + new FieldElement( 18512079,11319350,-20123124,15090309,18818594,5271736,-22727904,3666879,-23967430,-3299429 ), + new FieldElement( -6789020,-3146043,16192429,13241070,15898607,-14206114,-10084880,-6661110,-2403099,5276065 ) + ), + new GroupElementPreComp( + new FieldElement( 30169808,-5317648,26306206,-11750859,27814964,7069267,7152851,3684982,1449224,13082861 ), + new FieldElement( 10342826,3098505,2119311,193222,25702612,12233820,23697382,15056736,-21016438,-8202000 ), + new FieldElement( -33150110,3261608,22745853,7948688,19370557,-15177665,-26171976,6482814,-10300080,-11060101 ) + ), + new GroupElementPreComp( + new FieldElement( 32869458,-5408545,25609743,15678670,-10687769,-15471071,26112421,2521008,-22664288,6904815 ), + new FieldElement( 29506923,4457497,3377935,-9796444,-30510046,12935080,1561737,3841096,-29003639,-6657642 ), + new FieldElement( 10340844,-6630377,-18656632,-2278430,12621151,-13339055,30878497,-11824370,-25584551,5181966 ) + ), + new GroupElementPreComp( + new FieldElement( 25940115,-12658025,17324188,-10307374,-8671468,15029094,24396252,-16450922,-2322852,-12388574 ), + new FieldElement( -21765684,9916823,-1300409,4079498,-1028346,11909559,1782390,12641087,20603771,-6561742 ), + new FieldElement( -18882287,-11673380,24849422,11501709,13161720,-4768874,1925523,11914390,4662781,7820689 ) + ), + new GroupElementPreComp( + new FieldElement( 12241050,-425982,8132691,9393934,32846760,-1599620,29749456,12172924,16136752,15264020 ), + new FieldElement( -10349955,-14680563,-8211979,2330220,-17662549,-14545780,10658213,6671822,19012087,3772772 ), + new FieldElement( 3753511,-3421066,10617074,2028709,14841030,-6721664,28718732,-15762884,20527771,12988982 ) + ), + new GroupElementPreComp( + new FieldElement( -14822485,-5797269,-3707987,12689773,-898983,-10914866,-24183046,-10564943,3299665,-12424953 ), + new FieldElement( -16777703,-15253301,-9642417,4978983,3308785,8755439,6943197,6461331,-25583147,8991218 ), + new FieldElement( -17226263,1816362,-1673288,-6086439,31783888,-8175991,-32948145,7417950,-30242287,1507265 ) + ), + new GroupElementPreComp( + new FieldElement( 29692663,6829891,-10498800,4334896,20945975,-11906496,-28887608,8209391,14606362,-10647073 ), + new FieldElement( -3481570,8707081,32188102,5672294,22096700,1711240,-33020695,9761487,4170404,-2085325 ), + new FieldElement( -11587470,14855945,-4127778,-1531857,-26649089,15084046,22186522,16002000,-14276837,-8400798 ) + ), + new GroupElementPreComp( + new FieldElement( -4811456,13761029,-31703877,-2483919,-3312471,7869047,-7113572,-9620092,13240845,10965870 ), + new FieldElement( -7742563,-8256762,-14768334,-13656260,-23232383,12387166,4498947,14147411,29514390,4302863 ), + new FieldElement( -13413405,-12407859,20757302,-13801832,14785143,8976368,-5061276,-2144373,17846988,-13971927 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -2244452,-754728,-4597030,-1066309,-6247172,1455299,-21647728,-9214789,-5222701,12650267 ), + new FieldElement( -9906797,-16070310,21134160,12198166,-27064575,708126,387813,13770293,-19134326,10958663 ), + new FieldElement( 22470984,12369526,23446014,-5441109,-21520802,-9698723,-11772496,-11574455,-25083830,4271862 ) + ), + new GroupElementPreComp( + new FieldElement( -25169565,-10053642,-19909332,15361595,-5984358,2159192,75375,-4278529,-32526221,8469673 ), + new FieldElement( 15854970,4148314,-8893890,7259002,11666551,13824734,-30531198,2697372,24154791,-9460943 ), + new FieldElement( 15446137,-15806644,29759747,14019369,30811221,-9610191,-31582008,12840104,24913809,9815020 ) + ), + new GroupElementPreComp( + new FieldElement( -4709286,-5614269,-31841498,-12288893,-14443537,10799414,-9103676,13438769,18735128,9466238 ), + new FieldElement( 11933045,9281483,5081055,-5183824,-2628162,-4905629,-7727821,-10896103,-22728655,16199064 ), + new FieldElement( 14576810,379472,-26786533,-8317236,-29426508,-10812974,-102766,1876699,30801119,2164795 ) + ), + new GroupElementPreComp( + new FieldElement( 15995086,3199873,13672555,13712240,-19378835,-4647646,-13081610,-15496269,-13492807,1268052 ), + new FieldElement( -10290614,-3659039,-3286592,10948818,23037027,3794475,-3470338,-12600221,-17055369,3565904 ), + new FieldElement( 29210088,-9419337,-5919792,-4952785,10834811,-13327726,-16512102,-10820713,-27162222,-14030531 ) + ), + new GroupElementPreComp( + new FieldElement( -13161890,15508588,16663704,-8156150,-28349942,9019123,-29183421,-3769423,2244111,-14001979 ), + new FieldElement( -5152875,-3800936,-9306475,-6071583,16243069,14684434,-25673088,-16180800,13491506,4641841 ), + new FieldElement( 10813417,643330,-19188515,-728916,30292062,-16600078,27548447,-7721242,14476989,-12767431 ) + ), + new GroupElementPreComp( + new FieldElement( 10292079,9984945,6481436,8279905,-7251514,7032743,27282937,-1644259,-27912810,12651324 ), + new FieldElement( -31185513,-813383,22271204,11835308,10201545,15351028,17099662,3988035,21721536,-3148940 ), + new FieldElement( 10202177,-6545839,-31373232,-9574638,-32150642,-8119683,-12906320,3852694,13216206,14842320 ) + ), + new GroupElementPreComp( + new FieldElement( -15815640,-10601066,-6538952,-7258995,-6984659,-6581778,-31500847,13765824,-27434397,9900184 ), + new FieldElement( 14465505,-13833331,-32133984,-14738873,-27443187,12990492,33046193,15796406,-7051866,-8040114 ), + new FieldElement( 30924417,-8279620,6359016,-12816335,16508377,9071735,-25488601,15413635,9524356,-7018878 ) + ), + new GroupElementPreComp( + new FieldElement( 12274201,-13175547,32627641,-1785326,6736625,13267305,5237659,-5109483,15663516,4035784 ), + new FieldElement( -2951309,8903985,17349946,601635,-16432815,-4612556,-13732739,-15889334,-22258478,4659091 ), + new FieldElement( -16916263,-4952973,-30393711,-15158821,20774812,15897498,5736189,15026997,-2178256,-13455585 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -8858980,-2219056,28571666,-10155518,-474467,-10105698,-3801496,278095,23440562,-290208 ), + new FieldElement( 10226241,-5928702,15139956,120818,-14867693,5218603,32937275,11551483,-16571960,-7442864 ), + new FieldElement( 17932739,-12437276,-24039557,10749060,11316803,7535897,22503767,5561594,-3646624,3898661 ) + ), + new GroupElementPreComp( + new FieldElement( 7749907,-969567,-16339731,-16464,-25018111,15122143,-1573531,7152530,21831162,1245233 ), + new FieldElement( 26958459,-14658026,4314586,8346991,-5677764,11960072,-32589295,-620035,-30402091,-16716212 ), + new FieldElement( -12165896,9166947,33491384,13673479,29787085,13096535,6280834,14587357,-22338025,13987525 ) + ), + new GroupElementPreComp( + new FieldElement( -24349909,7778775,21116000,15572597,-4833266,-5357778,-4300898,-5124639,-7469781,-2858068 ), + new FieldElement( 9681908,-6737123,-31951644,13591838,-6883821,386950,31622781,6439245,-14581012,4091397 ), + new FieldElement( -8426427,1470727,-28109679,-1596990,3978627,-5123623,-19622683,12092163,29077877,-14741988 ) + ), + new GroupElementPreComp( + new FieldElement( 5269168,-6859726,-13230211,-8020715,25932563,1763552,-5606110,-5505881,-20017847,2357889 ), + new FieldElement( 32264008,-15407652,-5387735,-1160093,-2091322,-3946900,23104804,-12869908,5727338,189038 ), + new FieldElement( 14609123,-8954470,-6000566,-16622781,-14577387,-7743898,-26745169,10942115,-25888931,-14884697 ) + ), + new GroupElementPreComp( + new FieldElement( 20513500,5557931,-15604613,7829531,26413943,-2019404,-21378968,7471781,13913677,-5137875 ), + new FieldElement( -25574376,11967826,29233242,12948236,-6754465,4713227,-8940970,14059180,12878652,8511905 ), + new FieldElement( -25656801,3393631,-2955415,-7075526,-2250709,9366908,-30223418,6812974,5568676,-3127656 ) + ), + new GroupElementPreComp( + new FieldElement( 11630004,12144454,2116339,13606037,27378885,15676917,-17408753,-13504373,-14395196,8070818 ), + new FieldElement( 27117696,-10007378,-31282771,-5570088,1127282,12772488,-29845906,10483306,-11552749,-1028714 ), + new FieldElement( 10637467,-5688064,5674781,1072708,-26343588,-6982302,-1683975,9177853,-27493162,15431203 ) + ), + new GroupElementPreComp( + new FieldElement( 20525145,10892566,-12742472,12779443,-29493034,16150075,-28240519,14943142,-15056790,-7935931 ), + new FieldElement( -30024462,5626926,-551567,-9981087,753598,11981191,25244767,-3239766,-3356550,9594024 ), + new FieldElement( -23752644,2636870,-5163910,-10103818,585134,7877383,11345683,-6492290,13352335,-10977084 ) + ), + new GroupElementPreComp( + new FieldElement( -1931799,-5407458,3304649,-12884869,17015806,-4877091,-29783850,-7752482,-13215537,-319204 ), + new FieldElement( 20239939,6607058,6203985,3483793,-18386976,-779229,-20723742,15077870,-22750759,14523817 ), + new FieldElement( 27406042,-6041657,27423596,-4497394,4996214,10002360,-28842031,-4545494,-30172742,-4805667 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 11374242,12660715,17861383,-12540833,10935568,1099227,-13886076,-9091740,-27727044,11358504 ), + new FieldElement( -12730809,10311867,1510375,10778093,-2119455,-9145702,32676003,11149336,-26123651,4985768 ), + new FieldElement( -19096303,341147,-6197485,-239033,15756973,-8796662,-983043,13794114,-19414307,-15621255 ) + ), + new GroupElementPreComp( + new FieldElement( 6490081,11940286,25495923,-7726360,8668373,-8751316,3367603,6970005,-1691065,-9004790 ), + new FieldElement( 1656497,13457317,15370807,6364910,13605745,8362338,-19174622,-5475723,-16796596,-5031438 ), + new FieldElement( -22273315,-13524424,-64685,-4334223,-18605636,-10921968,-20571065,-7007978,-99853,-10237333 ) + ), + new GroupElementPreComp( + new FieldElement( 17747465,10039260,19368299,-4050591,-20630635,-16041286,31992683,-15857976,-29260363,-5511971 ), + new FieldElement( 31932027,-4986141,-19612382,16366580,22023614,88450,11371999,-3744247,4882242,-10626905 ), + new FieldElement( 29796507,37186,19818052,10115756,-11829032,3352736,18551198,3272828,-5190932,-4162409 ) + ), + new GroupElementPreComp( + new FieldElement( 12501286,4044383,-8612957,-13392385,-32430052,5136599,-19230378,-3529697,330070,-3659409 ), + new FieldElement( 6384877,2899513,17807477,7663917,-2358888,12363165,25366522,-8573892,-271295,12071499 ), + new FieldElement( -8365515,-4042521,25133448,-4517355,-6211027,2265927,-32769618,1936675,-5159697,3829363 ) + ), + new GroupElementPreComp( + new FieldElement( 28425966,-5835433,-577090,-4697198,-14217555,6870930,7921550,-6567787,26333140,14267664 ), + new FieldElement( -11067219,11871231,27385719,-10559544,-4585914,-11189312,10004786,-8709488,-21761224,8930324 ), + new FieldElement( -21197785,-16396035,25654216,-1725397,12282012,11008919,1541940,4757911,-26491501,-16408940 ) + ), + new GroupElementPreComp( + new FieldElement( 13537262,-7759490,-20604840,10961927,-5922820,-13218065,-13156584,6217254,-15943699,13814990 ), + new FieldElement( -17422573,15157790,18705543,29619,24409717,-260476,27361681,9257833,-1956526,-1776914 ), + new FieldElement( -25045300,-10191966,15366585,15166509,-13105086,8423556,-29171540,12361135,-18685978,4578290 ) + ), + new GroupElementPreComp( + new FieldElement( 24579768,3711570,1342322,-11180126,-27005135,14124956,-22544529,14074919,21964432,8235257 ), + new FieldElement( -6528613,-2411497,9442966,-5925588,12025640,-1487420,-2981514,-1669206,13006806,2355433 ), + new FieldElement( -16304899,-13605259,-6632427,-5142349,16974359,-10911083,27202044,1719366,1141648,-12796236 ) + ), + new GroupElementPreComp( + new FieldElement( -12863944,-13219986,-8318266,-11018091,-6810145,-4843894,13475066,-3133972,32674895,13715045 ), + new FieldElement( 11423335,-5468059,32344216,8962751,24989809,9241752,-13265253,16086212,-28740881,-15642093 ), + new FieldElement( -1409668,12530728,-6368726,10847387,19531186,-14132160,-11709148,7791794,-27245943,4383347 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -28970898,5271447,-1266009,-9736989,-12455236,16732599,-4862407,-4906449,27193557,6245191 ), + new FieldElement( -15193956,5362278,-1783893,2695834,4960227,12840725,23061898,3260492,22510453,8577507 ), + new FieldElement( -12632451,11257346,-32692994,13548177,-721004,10879011,31168030,13952092,-29571492,-3635906 ) + ), + new GroupElementPreComp( + new FieldElement( 3877321,-9572739,32416692,5405324,-11004407,-13656635,3759769,11935320,5611860,8164018 ), + new FieldElement( -16275802,14667797,15906460,12155291,-22111149,-9039718,32003002,-8832289,5773085,-8422109 ), + new FieldElement( -23788118,-8254300,1950875,8937633,18686727,16459170,-905725,12376320,31632953,190926 ) + ), + new GroupElementPreComp( + new FieldElement( -24593607,-16138885,-8423991,13378746,14162407,6901328,-8288749,4508564,-25341555,-3627528 ), + new FieldElement( 8884438,-5884009,6023974,10104341,-6881569,-4941533,18722941,-14786005,-1672488,827625 ), + new FieldElement( -32720583,-16289296,-32503547,7101210,13354605,2659080,-1800575,-14108036,-24878478,1541286 ) + ), + new GroupElementPreComp( + new FieldElement( 2901347,-1117687,3880376,-10059388,-17620940,-3612781,-21802117,-3567481,20456845,-1885033 ), + new FieldElement( 27019610,12299467,-13658288,-1603234,-12861660,-4861471,-19540150,-5016058,29439641,15138866 ), + new FieldElement( 21536104,-6626420,-32447818,-10690208,-22408077,5175814,-5420040,-16361163,7779328,109896 ) + ), + new GroupElementPreComp( + new FieldElement( 30279744,14648750,-8044871,6425558,13639621,-743509,28698390,12180118,23177719,-554075 ), + new FieldElement( 26572847,3405927,-31701700,12890905,-19265668,5335866,-6493768,2378492,4439158,-13279347 ), + new FieldElement( -22716706,3489070,-9225266,-332753,18875722,-1140095,14819434,-12731527,-17717757,-5461437 ) + ), + new GroupElementPreComp( + new FieldElement( -5056483,16566551,15953661,3767752,-10436499,15627060,-820954,2177225,8550082,-15114165 ), + new FieldElement( -18473302,16596775,-381660,15663611,22860960,15585581,-27844109,-3582739,-23260460,-8428588 ), + new FieldElement( -32480551,15707275,-8205912,-5652081,29464558,2713815,-22725137,15860482,-21902570,1494193 ) + ), + new GroupElementPreComp( + new FieldElement( -19562091,-14087393,-25583872,-9299552,13127842,759709,21923482,16529112,8742704,12967017 ), + new FieldElement( -28464899,1553205,32536856,-10473729,-24691605,-406174,-8914625,-2933896,-29903758,15553883 ), + new FieldElement( 21877909,3230008,9881174,10539357,-4797115,2841332,11543572,14513274,19375923,-12647961 ) + ), + new GroupElementPreComp( + new FieldElement( 8832269,-14495485,13253511,5137575,5037871,4078777,24880818,-6222716,2862653,9455043 ), + new FieldElement( 29306751,5123106,20245049,-14149889,9592566,8447059,-2077124,-2990080,15511449,4789663 ), + new FieldElement( -20679756,7004547,8824831,-9434977,-4045704,-3750736,-5754762,108893,23513200,16652362 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -33256173,4144782,-4476029,-6579123,10770039,-7155542,-6650416,-12936300,-18319198,10212860 ), + new FieldElement( 2756081,8598110,7383731,-6859892,22312759,-1105012,21179801,2600940,-9988298,-12506466 ), + new FieldElement( -24645692,13317462,-30449259,-15653928,21365574,-10869657,11344424,864440,-2499677,-16710063 ) + ), + new GroupElementPreComp( + new FieldElement( -26432803,6148329,-17184412,-14474154,18782929,-275997,-22561534,211300,2719757,4940997 ), + new FieldElement( -1323882,3911313,-6948744,14759765,-30027150,7851207,21690126,8518463,26699843,5276295 ), + new FieldElement( -13149873,-6429067,9396249,365013,24703301,-10488939,1321586,149635,-15452774,7159369 ) + ), + new GroupElementPreComp( + new FieldElement( 9987780,-3404759,17507962,9505530,9731535,-2165514,22356009,8312176,22477218,-8403385 ), + new FieldElement( 18155857,-16504990,19744716,9006923,15154154,-10538976,24256460,-4864995,-22548173,9334109 ), + new FieldElement( 2986088,-4911893,10776628,-3473844,10620590,-7083203,-21413845,14253545,-22587149,536906 ) + ), + new GroupElementPreComp( + new FieldElement( 4377756,8115836,24567078,15495314,11625074,13064599,7390551,10589625,10838060,-15420424 ), + new FieldElement( -19342404,867880,9277171,-3218459,-14431572,-1986443,19295826,-15796950,6378260,699185 ), + new FieldElement( 7895026,4057113,-7081772,-13077756,-17886831,-323126,-716039,15693155,-5045064,-13373962 ) + ), + new GroupElementPreComp( + new FieldElement( -7737563,-5869402,-14566319,-7406919,11385654,13201616,31730678,-10962840,-3918636,-9669325 ), + new FieldElement( 10188286,-15770834,-7336361,13427543,22223443,14896287,30743455,7116568,-21786507,5427593 ), + new FieldElement( 696102,13206899,27047647,-10632082,15285305,-9853179,10798490,-4578720,19236243,12477404 ) + ), + new GroupElementPreComp( + new FieldElement( -11229439,11243796,-17054270,-8040865,-788228,-8167967,-3897669,11180504,-23169516,7733644 ), + new FieldElement( 17800790,-14036179,-27000429,-11766671,23887827,3149671,23466177,-10538171,10322027,15313801 ), + new FieldElement( 26246234,11968874,32263343,-5468728,6830755,-13323031,-15794704,-101982,-24449242,10890804 ) + ), + new GroupElementPreComp( + new FieldElement( -31365647,10271363,-12660625,-6267268,16690207,-13062544,-14982212,16484931,25180797,-5334884 ), + new FieldElement( -586574,10376444,-32586414,-11286356,19801893,10997610,2276632,9482883,316878,13820577 ), + new FieldElement( -9882808,-4510367,-2115506,16457136,-11100081,11674996,30756178,-7515054,30696930,-3712849 ) + ), + new GroupElementPreComp( + new FieldElement( 32988917,-9603412,12499366,7910787,-10617257,-11931514,-7342816,-9985397,-32349517,7392473 ), + new FieldElement( -8855661,15927861,9866406,-3649411,-2396914,-16655781,-30409476,-9134995,25112947,-2926644 ), + new FieldElement( -2504044,-436966,25621774,-5678772,15085042,-5479877,-24884878,-13526194,5537438,-13914319 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -11225584,2320285,-9584280,10149187,-33444663,5808648,-14876251,-1729667,31234590,6090599 ), + new FieldElement( -9633316,116426,26083934,2897444,-6364437,-2688086,609721,15878753,-6970405,-9034768 ), + new FieldElement( -27757857,247744,-15194774,-9002551,23288161,-10011936,-23869595,6503646,20650474,1804084 ) + ), + new GroupElementPreComp( + new FieldElement( -27589786,15456424,8972517,8469608,15640622,4439847,3121995,-10329713,27842616,-202328 ), + new FieldElement( -15306973,2839644,22530074,10026331,4602058,5048462,28248656,5031932,-11375082,12714369 ), + new FieldElement( 20807691,-7270825,29286141,11421711,-27876523,-13868230,-21227475,1035546,-19733229,12796920 ) + ), + new GroupElementPreComp( + new FieldElement( 12076899,-14301286,-8785001,-11848922,-25012791,16400684,-17591495,-12899438,3480665,-15182815 ), + new FieldElement( -32361549,5457597,28548107,7833186,7303070,-11953545,-24363064,-15921875,-33374054,2771025 ), + new FieldElement( -21389266,421932,26597266,6860826,22486084,-6737172,-17137485,-4210226,-24552282,15673397 ) + ), + new GroupElementPreComp( + new FieldElement( -20184622,2338216,19788685,-9620956,-4001265,-8740893,-20271184,4733254,3727144,-12934448 ), + new FieldElement( 6120119,814863,-11794402,-622716,6812205,-15747771,2019594,7975683,31123697,-10958981 ), + new FieldElement( 30069250,-11435332,30434654,2958439,18399564,-976289,12296869,9204260,-16432438,9648165 ) + ), + new GroupElementPreComp( + new FieldElement( 32705432,-1550977,30705658,7451065,-11805606,9631813,3305266,5248604,-26008332,-11377501 ), + new FieldElement( 17219865,2375039,-31570947,-5575615,-19459679,9219903,294711,15298639,2662509,-16297073 ), + new FieldElement( -1172927,-7558695,-4366770,-4287744,-21346413,-8434326,32087529,-1222777,32247248,-14389861 ) + ), + new GroupElementPreComp( + new FieldElement( 14312628,1221556,17395390,-8700143,-4945741,-8684635,-28197744,-9637817,-16027623,-13378845 ), + new FieldElement( -1428825,-9678990,-9235681,6549687,-7383069,-468664,23046502,9803137,17597934,2346211 ), + new FieldElement( 18510800,15337574,26171504,981392,-22241552,7827556,-23491134,-11323352,3059833,-11782870 ) + ), + new GroupElementPreComp( + new FieldElement( 10141598,6082907,17829293,-1947643,9830092,13613136,-25556636,-5544586,-33502212,3592096 ), + new FieldElement( 33114168,-15889352,-26525686,-13343397,33076705,8716171,1151462,1521897,-982665,-6837803 ), + new FieldElement( -32939165,-4255815,23947181,-324178,-33072974,-12305637,-16637686,3891704,26353178,693168 ) + ), + new GroupElementPreComp( + new FieldElement( 30374239,1595580,-16884039,13186931,4600344,406904,9585294,-400668,31375464,14369965 ), + new FieldElement( -14370654,-7772529,1510301,6434173,-18784789,-6262728,32732230,-13108839,17901441,16011505 ), + new FieldElement( 18171223,-11934626,-12500402,15197122,-11038147,-15230035,-19172240,-16046376,8764035,12309598 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 5975908,-5243188,-19459362,-9681747,-11541277,14015782,-23665757,1228319,17544096,-10593782 ), + new FieldElement( 5811932,-1715293,3442887,-2269310,-18367348,-8359541,-18044043,-15410127,-5565381,12348900 ), + new FieldElement( -31399660,11407555,25755363,6891399,-3256938,14872274,-24849353,8141295,-10632534,-585479 ) + ), + new GroupElementPreComp( + new FieldElement( -12675304,694026,-5076145,13300344,14015258,-14451394,-9698672,-11329050,30944593,1130208 ), + new FieldElement( 8247766,-6710942,-26562381,-7709309,-14401939,-14648910,4652152,2488540,23550156,-271232 ), + new FieldElement( 17294316,-3788438,7026748,15626851,22990044,113481,2267737,-5908146,-408818,-137719 ) + ), + new GroupElementPreComp( + new FieldElement( 16091085,-16253926,18599252,7340678,2137637,-1221657,-3364161,14550936,3260525,-7166271 ), + new FieldElement( -4910104,-13332887,18550887,10864893,-16459325,-7291596,-23028869,-13204905,-12748722,2701326 ), + new FieldElement( -8574695,16099415,4629974,-16340524,-20786213,-6005432,-10018363,9276971,11329923,1862132 ) + ), + new GroupElementPreComp( + new FieldElement( 14763076,-15903608,-30918270,3689867,3511892,10313526,-21951088,12219231,-9037963,-940300 ), + new FieldElement( 8894987,-3446094,6150753,3013931,301220,15693451,-31981216,-2909717,-15438168,11595570 ), + new FieldElement( 15214962,3537601,-26238722,-14058872,4418657,-15230761,13947276,10730794,-13489462,-4363670 ) + ), + new GroupElementPreComp( + new FieldElement( -2538306,7682793,32759013,263109,-29984731,-7955452,-22332124,-10188635,977108,699994 ), + new FieldElement( -12466472,4195084,-9211532,550904,-15565337,12917920,19118110,-439841,-30534533,-14337913 ), + new FieldElement( 31788461,-14507657,4799989,7372237,8808585,-14747943,9408237,-10051775,12493932,-5409317 ) + ), + new GroupElementPreComp( + new FieldElement( -25680606,5260744,-19235809,-6284470,-3695942,16566087,27218280,2607121,29375955,6024730 ), + new FieldElement( 842132,-2794693,-4763381,-8722815,26332018,-12405641,11831880,6985184,-9940361,2854096 ), + new FieldElement( -4847262,-7969331,2516242,-5847713,9695691,-7221186,16512645,960770,12121869,16648078 ) + ), + new GroupElementPreComp( + new FieldElement( -15218652,14667096,-13336229,2013717,30598287,-464137,-31504922,-7882064,20237806,2838411 ), + new FieldElement( -19288047,4453152,15298546,-16178388,22115043,-15972604,12544294,-13470457,1068881,-12499905 ), + new FieldElement( -9558883,-16518835,33238498,13506958,30505848,-1114596,-8486907,-2630053,12521378,4845654 ) + ), + new GroupElementPreComp( + new FieldElement( -28198521,10744108,-2958380,10199664,7759311,-13088600,3409348,-873400,-6482306,-12885870 ), + new FieldElement( -23561822,6230156,-20382013,10655314,-24040585,-11621172,10477734,-1240216,-3113227,13974498 ), + new FieldElement( 12966261,15550616,-32038948,-1615346,21025980,-629444,5642325,7188737,18895762,12629579 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 14741879,-14946887,22177208,-11721237,1279741,8058600,11758140,789443,32195181,3895677 ), + new FieldElement( 10758205,15755439,-4509950,9243698,-4879422,6879879,-2204575,-3566119,-8982069,4429647 ), + new FieldElement( -2453894,15725973,-20436342,-10410672,-5803908,-11040220,-7135870,-11642895,18047436,-15281743 ) + ), + new GroupElementPreComp( + new FieldElement( -25173001,-11307165,29759956,11776784,-22262383,-15820455,10993114,-12850837,-17620701,-9408468 ), + new FieldElement( 21987233,700364,-24505048,14972008,-7774265,-5718395,32155026,2581431,-29958985,8773375 ), + new FieldElement( -25568350,454463,-13211935,16126715,25240068,8594567,20656846,12017935,-7874389,-13920155 ) + ), + new GroupElementPreComp( + new FieldElement( 6028182,6263078,-31011806,-11301710,-818919,2461772,-31841174,-5468042,-1721788,-2776725 ), + new FieldElement( -12278994,16624277,987579,-5922598,32908203,1248608,7719845,-4166698,28408820,6816612 ), + new FieldElement( -10358094,-8237829,19549651,-12169222,22082623,16147817,20613181,13982702,-10339570,5067943 ) + ), + new GroupElementPreComp( + new FieldElement( -30505967,-3821767,12074681,13582412,-19877972,2443951,-19719286,12746132,5331210,-10105944 ), + new FieldElement( 30528811,3601899,-1957090,4619785,-27361822,-15436388,24180793,-12570394,27679908,-1648928 ), + new FieldElement( 9402404,-13957065,32834043,10838634,-26580150,-13237195,26653274,-8685565,22611444,-12715406 ) + ), + new GroupElementPreComp( + new FieldElement( 22190590,1118029,22736441,15130463,-30460692,-5991321,19189625,-4648942,4854859,6622139 ), + new FieldElement( -8310738,-2953450,-8262579,-3388049,-10401731,-271929,13424426,-3567227,26404409,13001963 ), + new FieldElement( -31241838,-15415700,-2994250,8939346,11562230,-12840670,-26064365,-11621720,-15405155,11020693 ) + ), + new GroupElementPreComp( + new FieldElement( 1866042,-7949489,-7898649,-10301010,12483315,13477547,3175636,-12424163,28761762,1406734 ), + new FieldElement( -448555,-1777666,13018551,3194501,-9580420,-11161737,24760585,-4347088,25577411,-13378680 ), + new FieldElement( -24290378,4759345,-690653,-1852816,2066747,10693769,-29595790,9884936,-9368926,4745410 ) + ), + new GroupElementPreComp( + new FieldElement( -9141284,6049714,-19531061,-4341411,-31260798,9944276,-15462008,-11311852,10931924,-11931931 ), + new FieldElement( -16561513,14112680,-8012645,4817318,-8040464,-11414606,-22853429,10856641,-20470770,13434654 ), + new FieldElement( 22759489,-10073434,-16766264,-1871422,13637442,-10168091,1765144,-12654326,28445307,-5364710 ) + ), + new GroupElementPreComp( + new FieldElement( 29875063,12493613,2795536,-3786330,1710620,15181182,-10195717,-8788675,9074234,1167180 ), + new FieldElement( -26205683,11014233,-9842651,-2635485,-26908120,7532294,-18716888,-9535498,3843903,9367684 ), + new FieldElement( -10969595,-6403711,9591134,9582310,11349256,108879,16235123,8601684,-139197,4242895 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 22092954,-13191123,-2042793,-11968512,32186753,-11517388,-6574341,2470660,-27417366,16625501 ), + new FieldElement( -11057722,3042016,13770083,-9257922,584236,-544855,-7770857,2602725,-27351616,14247413 ), + new FieldElement( 6314175,-10264892,-32772502,15957557,-10157730,168750,-8618807,14290061,27108877,-1180880 ) + ), + new GroupElementPreComp( + new FieldElement( -8586597,-7170966,13241782,10960156,-32991015,-13794596,33547976,-11058889,-27148451,981874 ), + new FieldElement( 22833440,9293594,-32649448,-13618667,-9136966,14756819,-22928859,-13970780,-10479804,-16197962 ), + new FieldElement( -7768587,3326786,-28111797,10783824,19178761,14905060,22680049,13906969,-15933690,3797899 ) + ), + new GroupElementPreComp( + new FieldElement( 21721356,-4212746,-12206123,9310182,-3882239,-13653110,23740224,-2709232,20491983,-8042152 ), + new FieldElement( 9209270,-15135055,-13256557,-6167798,-731016,15289673,25947805,15286587,30997318,-6703063 ), + new FieldElement( 7392032,16618386,23946583,-8039892,-13265164,-1533858,-14197445,-2321576,17649998,-250080 ) + ), + new GroupElementPreComp( + new FieldElement( -9301088,-14193827,30609526,-3049543,-25175069,-1283752,-15241566,-9525724,-2233253,7662146 ), + new FieldElement( -17558673,1763594,-33114336,15908610,-30040870,-12174295,7335080,-8472199,-3174674,3440183 ), + new FieldElement( -19889700,-5977008,-24111293,-9688870,10799743,-16571957,40450,-4431835,4862400,1133 ) + ), + new GroupElementPreComp( + new FieldElement( -32856209,-7873957,-5422389,14860950,-16319031,7956142,7258061,311861,-30594991,-7379421 ), + new FieldElement( -3773428,-1565936,28985340,7499440,24445838,9325937,29727763,16527196,18278453,15405622 ), + new FieldElement( -4381906,8508652,-19898366,-3674424,-5984453,15149970,-13313598,843523,-21875062,13626197 ) + ), + new GroupElementPreComp( + new FieldElement( 2281448,-13487055,-10915418,-2609910,1879358,16164207,-10783882,3953792,13340839,15928663 ), + new FieldElement( 31727126,-7179855,-18437503,-8283652,2875793,-16390330,-25269894,-7014826,-23452306,5964753 ), + new FieldElement( 4100420,-5959452,-17179337,6017714,-18705837,12227141,-26684835,11344144,2538215,-7570755 ) + ), + new GroupElementPreComp( + new FieldElement( -9433605,6123113,11159803,-2156608,30016280,14966241,-20474983,1485421,-629256,-15958862 ), + new FieldElement( -26804558,4260919,11851389,9658551,-32017107,16367492,-20205425,-13191288,11659922,-11115118 ), + new FieldElement( 26180396,10015009,-30844224,-8581293,5418197,9480663,2231568,-10170080,33100372,-1306171 ) + ), + new GroupElementPreComp( + new FieldElement( 15121113,-5201871,-10389905,15427821,-27509937,-15992507,21670947,4486675,-5931810,-14466380 ), + new FieldElement( 16166486,-9483733,-11104130,6023908,-31926798,-1364923,2340060,-16254968,-10735770,-10039824 ), + new FieldElement( 28042865,-3557089,-12126526,12259706,-3717498,-6945899,6766453,-8689599,18036436,5803270 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -817581,6763912,11803561,1585585,10958447,-2671165,23855391,4598332,-6159431,-14117438 ), + new FieldElement( -31031306,-14256194,17332029,-2383520,31312682,-5967183,696309,50292,-20095739,11763584 ), + new FieldElement( -594563,-2514283,-32234153,12643980,12650761,14811489,665117,-12613632,-19773211,-10713562 ) + ), + new GroupElementPreComp( + new FieldElement( 30464590,-11262872,-4127476,-12734478,19835327,-7105613,-24396175,2075773,-17020157,992471 ), + new FieldElement( 18357185,-6994433,7766382,16342475,-29324918,411174,14578841,8080033,-11574335,-10601610 ), + new FieldElement( 19598397,10334610,12555054,2555664,18821899,-10339780,21873263,16014234,26224780,16452269 ) + ), + new GroupElementPreComp( + new FieldElement( -30223925,5145196,5944548,16385966,3976735,2009897,-11377804,-7618186,-20533829,3698650 ), + new FieldElement( 14187449,3448569,-10636236,-10810935,-22663880,-3433596,7268410,-10890444,27394301,12015369 ), + new FieldElement( 19695761,16087646,28032085,12999827,6817792,11427614,20244189,-1312777,-13259127,-3402461 ) + ), + new GroupElementPreComp( + new FieldElement( 30860103,12735208,-1888245,-4699734,-16974906,2256940,-8166013,12298312,-8550524,-10393462 ), + new FieldElement( -5719826,-11245325,-1910649,15569035,26642876,-7587760,-5789354,-15118654,-4976164,12651793 ), + new FieldElement( -2848395,9953421,11531313,-5282879,26895123,-12697089,-13118820,-16517902,9768698,-2533218 ) + ), + new GroupElementPreComp( + new FieldElement( -24719459,1894651,-287698,-4704085,15348719,-8156530,32767513,12765450,4940095,10678226 ), + new FieldElement( 18860224,15980149,-18987240,-1562570,-26233012,-11071856,-7843882,13944024,-24372348,16582019 ), + new FieldElement( -15504260,4970268,-29893044,4175593,-20993212,-2199756,-11704054,15444560,-11003761,7989037 ) + ), + new GroupElementPreComp( + new FieldElement( 31490452,5568061,-2412803,2182383,-32336847,4531686,-32078269,6200206,-19686113,-14800171 ), + new FieldElement( -17308668,-15879940,-31522777,-2831,-32887382,16375549,8680158,-16371713,28550068,-6857132 ), + new FieldElement( -28126887,-5688091,16837845,-1820458,-6850681,12700016,-30039981,4364038,1155602,5988841 ) + ), + new GroupElementPreComp( + new FieldElement( 21890435,-13272907,-12624011,12154349,-7831873,15300496,23148983,-4470481,24618407,8283181 ), + new FieldElement( -33136107,-10512751,9975416,6841041,-31559793,16356536,3070187,-7025928,1466169,10740210 ), + new FieldElement( -1509399,-15488185,-13503385,-10655916,32799044,909394,-13938903,-5779719,-32164649,-15327040 ) + ), + new GroupElementPreComp( + new FieldElement( 3960823,-14267803,-28026090,-15918051,-19404858,13146868,15567327,951507,-3260321,-573935 ), + new FieldElement( 24740841,5052253,-30094131,8961361,25877428,6165135,-24368180,14397372,-7380369,-6144105 ), + new FieldElement( -28888365,3510803,-28103278,-1158478,-11238128,-10631454,-15441463,-14453128,-1625486,-6494814 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 793299,-9230478,8836302,-6235707,-27360908,-2369593,33152843,-4885251,-9906200,-621852 ), + new FieldElement( 5666233,525582,20782575,-8038419,-24538499,14657740,16099374,1468826,-6171428,-15186581 ), + new FieldElement( -4859255,-3779343,-2917758,-6748019,7778750,11688288,-30404353,-9871238,-1558923,-9863646 ) + ), + new GroupElementPreComp( + new FieldElement( 10896332,-7719704,824275,472601,-19460308,3009587,25248958,14783338,-30581476,-15757844 ), + new FieldElement( 10566929,12612572,-31944212,11118703,-12633376,12362879,21752402,8822496,24003793,14264025 ), + new FieldElement( 27713862,-7355973,-11008240,9227530,27050101,2504721,23886875,-13117525,13958495,-5732453 ) + ), + new GroupElementPreComp( + new FieldElement( -23481610,4867226,-27247128,3900521,29838369,-8212291,-31889399,-10041781,7340521,-15410068 ), + new FieldElement( 4646514,-8011124,-22766023,-11532654,23184553,8566613,31366726,-1381061,-15066784,-10375192 ), + new FieldElement( -17270517,12723032,-16993061,14878794,21619651,-6197576,27584817,3093888,-8843694,3849921 ) + ), + new GroupElementPreComp( + new FieldElement( -9064912,2103172,25561640,-15125738,-5239824,9582958,32477045,-9017955,5002294,-15550259 ), + new FieldElement( -12057553,-11177906,21115585,-13365155,8808712,-12030708,16489530,13378448,-25845716,12741426 ), + new FieldElement( -5946367,10645103,-30911586,15390284,-3286982,-7118677,24306472,15852464,28834118,-7646072 ) + ), + new GroupElementPreComp( + new FieldElement( -17335748,-9107057,-24531279,9434953,-8472084,-583362,-13090771,455841,20461858,5491305 ), + new FieldElement( 13669248,-16095482,-12481974,-10203039,-14569770,-11893198,-24995986,11293807,-28588204,-9421832 ), + new FieldElement( 28497928,6272777,-33022994,14470570,8906179,-1225630,18504674,-14165166,29867745,-8795943 ) + ), + new GroupElementPreComp( + new FieldElement( -16207023,13517196,-27799630,-13697798,24009064,-6373891,-6367600,-13175392,22853429,-4012011 ), + new FieldElement( 24191378,16712145,-13931797,15217831,14542237,1646131,18603514,-11037887,12876623,-2112447 ), + new FieldElement( 17902668,4518229,-411702,-2829247,26878217,5258055,-12860753,608397,16031844,3723494 ) + ), + new GroupElementPreComp( + new FieldElement( -28632773,12763728,-20446446,7577504,33001348,-13017745,17558842,-7872890,23896954,-4314245 ), + new FieldElement( -20005381,-12011952,31520464,605201,2543521,5991821,-2945064,7229064,-9919646,-8826859 ), + new FieldElement( 28816045,298879,-28165016,-15920938,19000928,-1665890,-12680833,-2949325,-18051778,-2082915 ) + ), + new GroupElementPreComp( + new FieldElement( 16000882,-344896,3493092,-11447198,-29504595,-13159789,12577740,16041268,-19715240,7847707 ), + new FieldElement( 10151868,10572098,27312476,7922682,14825339,4723128,-32855931,-6519018,-10020567,3852848 ), + new FieldElement( -11430470,15697596,-21121557,-4420647,5386314,15063598,16514493,-15932110,29330899,-15076224 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -25499735,-4378794,-15222908,-6901211,16615731,2051784,3303702,15490,-27548796,12314391 ), + new FieldElement( 15683520,-6003043,18109120,-9980648,15337968,-5997823,-16717435,15921866,16103996,-3731215 ), + new FieldElement( -23169824,-10781249,13588192,-1628807,-3798557,-1074929,-19273607,5402699,-29815713,-9841101 ) + ), + new GroupElementPreComp( + new FieldElement( 23190676,2384583,-32714340,3462154,-29903655,-1529132,-11266856,8911517,-25205859,2739713 ), + new FieldElement( 21374101,-3554250,-33524649,9874411,15377179,11831242,-33529904,6134907,4931255,11987849 ), + new FieldElement( -7732,-2978858,-16223486,7277597,105524,-322051,-31480539,13861388,-30076310,10117930 ) + ), + new GroupElementPreComp( + new FieldElement( -29501170,-10744872,-26163768,13051539,-25625564,5089643,-6325503,6704079,12890019,15728940 ), + new FieldElement( -21972360,-11771379,-951059,-4418840,14704840,2695116,903376,-10428139,12885167,8311031 ), + new FieldElement( -17516482,5352194,10384213,-13811658,7506451,13453191,26423267,4384730,1888765,-5435404 ) + ), + new GroupElementPreComp( + new FieldElement( -25817338,-3107312,-13494599,-3182506,30896459,-13921729,-32251644,-12707869,-19464434,-3340243 ), + new FieldElement( -23607977,-2665774,-526091,4651136,5765089,4618330,6092245,14845197,17151279,-9854116 ), + new FieldElement( -24830458,-12733720,-15165978,10367250,-29530908,-265356,22825805,-7087279,-16866484,16176525 ) + ), + new GroupElementPreComp( + new FieldElement( -23583256,6564961,20063689,3798228,-4740178,7359225,2006182,-10363426,-28746253,-10197509 ), + new FieldElement( -10626600,-4486402,-13320562,-5125317,3432136,-6393229,23632037,-1940610,32808310,1099883 ), + new FieldElement( 15030977,5768825,-27451236,-2887299,-6427378,-15361371,-15277896,-6809350,2051441,-15225865 ) + ), + new GroupElementPreComp( + new FieldElement( -3362323,-7239372,7517890,9824992,23555850,295369,5148398,-14154188,-22686354,16633660 ), + new FieldElement( 4577086,-16752288,13249841,-15304328,19958763,-14537274,18559670,-10759549,8402478,-9864273 ), + new FieldElement( -28406330,-1051581,-26790155,-907698,-17212414,-11030789,9453451,-14980072,17983010,9967138 ) + ), + new GroupElementPreComp( + new FieldElement( -25762494,6524722,26585488,9969270,24709298,1220360,-1677990,7806337,17507396,3651560 ), + new FieldElement( -10420457,-4118111,14584639,15971087,-15768321,8861010,26556809,-5574557,-18553322,-11357135 ), + new FieldElement( 2839101,14284142,4029895,3472686,14402957,12689363,-26642121,8459447,-5605463,-7621941 ) + ), + new GroupElementPreComp( + new FieldElement( -4839289,-3535444,9744961,2871048,25113978,3187018,-25110813,-849066,17258084,-7977739 ), + new FieldElement( 18164541,-10595176,-17154882,-1542417,19237078,-9745295,23357533,-15217008,26908270,12150756 ), + new FieldElement( -30264870,-7647865,5112249,-7036672,-1499807,-6974257,43168,-5537701,-32302074,16215819 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -6898905,9824394,-12304779,-4401089,-31397141,-6276835,32574489,12532905,-7503072,-8675347 ), + new FieldElement( -27343522,-16515468,-27151524,-10722951,946346,16291093,254968,7168080,21676107,-1943028 ), + new FieldElement( 21260961,-8424752,-16831886,-11920822,-23677961,3968121,-3651949,-6215466,-3556191,-7913075 ) + ), + new GroupElementPreComp( + new FieldElement( 16544754,13250366,-16804428,15546242,-4583003,12757258,-2462308,-8680336,-18907032,-9662799 ), + new FieldElement( -2415239,-15577728,18312303,4964443,-15272530,-12653564,26820651,16690659,25459437,-4564609 ), + new FieldElement( -25144690,11425020,28423002,-11020557,-6144921,-15826224,9142795,-2391602,-6432418,-1644817 ) + ), + new GroupElementPreComp( + new FieldElement( -23104652,6253476,16964147,-3768872,-25113972,-12296437,-27457225,-16344658,6335692,7249989 ), + new FieldElement( -30333227,13979675,7503222,-12368314,-11956721,-4621693,-30272269,2682242,25993170,-12478523 ), + new FieldElement( 4364628,5930691,32304656,-10044554,-8054781,15091131,22857016,-10598955,31820368,15075278 ) + ), + new GroupElementPreComp( + new FieldElement( 31879134,-8918693,17258761,90626,-8041836,-4917709,24162788,-9650886,-17970238,12833045 ), + new FieldElement( 19073683,14851414,-24403169,-11860168,7625278,11091125,-19619190,2074449,-9413939,14905377 ), + new FieldElement( 24483667,-11935567,-2518866,-11547418,-1553130,15355506,-25282080,9253129,27628530,-7555480 ) + ), + new GroupElementPreComp( + new FieldElement( 17597607,8340603,19355617,552187,26198470,-3176583,4593324,-9157582,-14110875,15297016 ), + new FieldElement( 510886,14337390,-31785257,16638632,6328095,2713355,-20217417,-11864220,8683221,2921426 ), + new FieldElement( 18606791,11874196,27155355,-5281482,-24031742,6265446,-25178240,-1278924,4674690,13890525 ) + ), + new GroupElementPreComp( + new FieldElement( 13609624,13069022,-27372361,-13055908,24360586,9592974,14977157,9835105,4389687,288396 ), + new FieldElement( 9922506,-519394,13613107,5883594,-18758345,-434263,-12304062,8317628,23388070,16052080 ), + new FieldElement( 12720016,11937594,-31970060,-5028689,26900120,8561328,-20155687,-11632979,-14754271,-10812892 ) + ), + new GroupElementPreComp( + new FieldElement( 15961858,14150409,26716931,-665832,-22794328,13603569,11829573,7467844,-28822128,929275 ), + new FieldElement( 11038231,-11582396,-27310482,-7316562,-10498527,-16307831,-23479533,-9371869,-21393143,2465074 ), + new FieldElement( 20017163,-4323226,27915242,1529148,12396362,15675764,13817261,-9658066,2463391,-4622140 ) + ), + new GroupElementPreComp( + new FieldElement( -16358878,-12663911,-12065183,4996454,-1256422,1073572,9583558,12851107,4003896,12673717 ), + new FieldElement( -1731589,-15155870,-3262930,16143082,19294135,13385325,14741514,-9103726,7903886,2348101 ), + new FieldElement( 24536016,-16515207,12715592,-3862155,1511293,10047386,-3842346,-7129159,-28377538,10048127 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -12622226,-6204820,30718825,2591312,-10617028,12192840,18873298,-7297090,-32297756,15221632 ), + new FieldElement( -26478122,-11103864,11546244,-1852483,9180880,7656409,-21343950,2095755,29769758,6593415 ), + new FieldElement( -31994208,-2907461,4176912,3264766,12538965,-868111,26312345,-6118678,30958054,8292160 ) + ), + new GroupElementPreComp( + new FieldElement( 31429822,-13959116,29173532,15632448,12174511,-2760094,32808831,3977186,26143136,-3148876 ), + new FieldElement( 22648901,1402143,-22799984,13746059,7936347,365344,-8668633,-1674433,-3758243,-2304625 ), + new FieldElement( -15491917,8012313,-2514730,-12702462,-23965846,-10254029,-1612713,-1535569,-16664475,8194478 ) + ), + new GroupElementPreComp( + new FieldElement( 27338066,-7507420,-7414224,10140405,-19026427,-6589889,27277191,8855376,28572286,3005164 ), + new FieldElement( 26287124,4821776,25476601,-4145903,-3764513,-15788984,-18008582,1182479,-26094821,-13079595 ), + new FieldElement( -7171154,3178080,23970071,6201893,-17195577,-4489192,-21876275,-13982627,32208683,-1198248 ) + ), + new GroupElementPreComp( + new FieldElement( -16657702,2817643,-10286362,14811298,6024667,13349505,-27315504,-10497842,-27672585,-11539858 ), + new FieldElement( 15941029,-9405932,-21367050,8062055,31876073,-238629,-15278393,-1444429,15397331,-4130193 ), + new FieldElement( 8934485,-13485467,-23286397,-13423241,-32446090,14047986,31170398,-1441021,-27505566,15087184 ) + ), + new GroupElementPreComp( + new FieldElement( -18357243,-2156491,24524913,-16677868,15520427,-6360776,-15502406,11461896,16788528,-5868942 ), + new FieldElement( -1947386,16013773,21750665,3714552,-17401782,-16055433,-3770287,-10323320,31322514,-11615635 ), + new FieldElement( 21426655,-5650218,-13648287,-5347537,-28812189,-4920970,-18275391,-14621414,13040862,-12112948 ) + ), + new GroupElementPreComp( + new FieldElement( 11293895,12478086,-27136401,15083750,-29307421,14748872,14555558,-13417103,1613711,4896935 ), + new FieldElement( -25894883,15323294,-8489791,-8057900,25967126,-13425460,2825960,-4897045,-23971776,-11267415 ), + new FieldElement( -15924766,-5229880,-17443532,6410664,3622847,10243618,20615400,12405433,-23753030,-8436416 ) + ), + new GroupElementPreComp( + new FieldElement( -7091295,12556208,-20191352,9025187,-17072479,4333801,4378436,2432030,23097949,-566018 ), + new FieldElement( 4565804,-16025654,20084412,-7842817,1724999,189254,24767264,10103221,-18512313,2424778 ), + new FieldElement( 366633,-11976806,8173090,-6890119,30788634,5745705,-7168678,1344109,-3642553,12412659 ) + ), + new GroupElementPreComp( + new FieldElement( -24001791,7690286,14929416,-168257,-32210835,-13412986,24162697,-15326504,-3141501,11179385 ), + new FieldElement( 18289522,-14724954,8056945,16430056,-21729724,7842514,-6001441,-1486897,-18684645,-11443503 ), + new FieldElement( 476239,6601091,-6152790,-9723375,17503545,-4863900,27672959,13403813,11052904,5219329 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 20678546,-8375738,-32671898,8849123,-5009758,14574752,31186971,-3973730,9014762,-8579056 ), + new FieldElement( -13644050,-10350239,-15962508,5075808,-1514661,-11534600,-33102500,9160280,8473550,-3256838 ), + new FieldElement( 24900749,14435722,17209120,-15292541,-22592275,9878983,-7689309,-16335821,-24568481,11788948 ) + ), + new GroupElementPreComp( + new FieldElement( -3118155,-11395194,-13802089,14797441,9652448,-6845904,-20037437,10410733,-24568470,-1458691 ), + new FieldElement( -15659161,16736706,-22467150,10215878,-9097177,7563911,11871841,-12505194,-18513325,8464118 ), + new FieldElement( -23400612,8348507,-14585951,-861714,-3950205,-6373419,14325289,8628612,33313881,-8370517 ) + ), + new GroupElementPreComp( + new FieldElement( -20186973,-4967935,22367356,5271547,-1097117,-4788838,-24805667,-10236854,-8940735,-5818269 ), + new FieldElement( -6948785,-1795212,-32625683,-16021179,32635414,-7374245,15989197,-12838188,28358192,-4253904 ), + new FieldElement( -23561781,-2799059,-32351682,-1661963,-9147719,10429267,-16637684,4072016,-5351664,5596589 ) + ), + new GroupElementPreComp( + new FieldElement( -28236598,-3390048,12312896,6213178,3117142,16078565,29266239,2557221,1768301,15373193 ), + new FieldElement( -7243358,-3246960,-4593467,-7553353,-127927,-912245,-1090902,-4504991,-24660491,3442910 ), + new FieldElement( -30210571,5124043,14181784,8197961,18964734,-11939093,22597931,7176455,-18585478,13365930 ) + ), + new GroupElementPreComp( + new FieldElement( -7877390,-1499958,8324673,4690079,6261860,890446,24538107,-8570186,-9689599,-3031667 ), + new FieldElement( 25008904,-10771599,-4305031,-9638010,16265036,15721635,683793,-11823784,15723479,-15163481 ), + new FieldElement( -9660625,12374379,-27006999,-7026148,-7724114,-12314514,11879682,5400171,519526,-1235876 ) + ), + new GroupElementPreComp( + new FieldElement( 22258397,-16332233,-7869817,14613016,-22520255,-2950923,-20353881,7315967,16648397,7605640 ), + new FieldElement( -8081308,-8464597,-8223311,9719710,19259459,-15348212,23994942,-5281555,-9468848,4763278 ), + new FieldElement( -21699244,9220969,-15730624,1084137,-25476107,-2852390,31088447,-7764523,-11356529,728112 ) + ), + new GroupElementPreComp( + new FieldElement( 26047220,-11751471,-6900323,-16521798,24092068,9158119,-4273545,-12555558,-29365436,-5498272 ), + new FieldElement( 17510331,-322857,5854289,8403524,17133918,-3112612,-28111007,12327945,10750447,10014012 ), + new FieldElement( -10312768,3936952,9156313,-8897683,16498692,-994647,-27481051,-666732,3424691,7540221 ) + ), + new GroupElementPreComp( + new FieldElement( 30322361,-6964110,11361005,-4143317,7433304,4989748,-7071422,-16317219,-9244265,15258046 ), + new FieldElement( 13054562,-2779497,19155474,469045,-12482797,4566042,5631406,2711395,1062915,-5136345 ), + new FieldElement( -19240248,-11254599,-29509029,-7499965,-5835763,13005411,-6066489,12194497,32960380,1459310 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 19852034,7027924,23669353,10020366,8586503,-6657907,394197,-6101885,18638003,-11174937 ), + new FieldElement( 31395534,15098109,26581030,8030562,-16527914,-5007134,9012486,-7584354,-6643087,-5442636 ), + new FieldElement( -9192165,-2347377,-1997099,4529534,25766844,607986,-13222,9677543,-32294889,-6456008 ) + ), + new GroupElementPreComp( + new FieldElement( -2444496,-149937,29348902,8186665,1873760,12489863,-30934579,-7839692,-7852844,-8138429 ), + new FieldElement( -15236356,-15433509,7766470,746860,26346930,-10221762,-27333451,10754588,-9431476,5203576 ), + new FieldElement( 31834314,14135496,-770007,5159118,20917671,-16768096,-7467973,-7337524,31809243,7347066 ) + ), + new GroupElementPreComp( + new FieldElement( -9606723,-11874240,20414459,13033986,13716524,-11691881,19797970,-12211255,15192876,-2087490 ), + new FieldElement( -12663563,-2181719,1168162,-3804809,26747877,-14138091,10609330,12694420,33473243,-13382104 ), + new FieldElement( 33184999,11180355,15832085,-11385430,-1633671,225884,15089336,-11023903,-6135662,14480053 ) + ), + new GroupElementPreComp( + new FieldElement( 31308717,-5619998,31030840,-1897099,15674547,-6582883,5496208,13685227,27595050,8737275 ), + new FieldElement( -20318852,-15150239,10933843,-16178022,8335352,-7546022,-31008351,-12610604,26498114,66511 ), + new FieldElement( 22644454,-8761729,-16671776,4884562,-3105614,-13559366,30540766,-4286747,-13327787,-7515095 ) + ), + new GroupElementPreComp( + new FieldElement( -28017847,9834845,18617207,-2681312,-3401956,-13307506,8205540,13585437,-17127465,15115439 ), + new FieldElement( 23711543,-672915,31206561,-8362711,6164647,-9709987,-33535882,-1426096,8236921,16492939 ), + new FieldElement( -23910559,-13515526,-26299483,-4503841,25005590,-7687270,19574902,10071562,6708380,-6222424 ) + ), + new GroupElementPreComp( + new FieldElement( 2101391,-4930054,19702731,2367575,-15427167,1047675,5301017,9328700,29955601,-11678310 ), + new FieldElement( 3096359,9271816,-21620864,-15521844,-14847996,-7592937,-25892142,-12635595,-9917575,6216608 ), + new FieldElement( -32615849,338663,-25195611,2510422,-29213566,-13820213,24822830,-6146567,-26767480,7525079 ) + ), + new GroupElementPreComp( + new FieldElement( -23066649,-13985623,16133487,-7896178,-3389565,778788,-910336,-2782495,-19386633,11994101 ), + new FieldElement( 21691500,-13624626,-641331,-14367021,3285881,-3483596,-25064666,9718258,-7477437,13381418 ), + new FieldElement( 18445390,-4202236,14979846,11622458,-1727110,-3582980,23111648,-6375247,28535282,15779576 ) + ), + new GroupElementPreComp( + new FieldElement( 30098053,3089662,-9234387,16662135,-21306940,11308411,-14068454,12021730,9955285,-16303356 ), + new FieldElement( 9734894,-14576830,-7473633,-9138735,2060392,11313496,-18426029,9924399,20194861,13380996 ), + new FieldElement( -26378102,-7965207,-22167821,15789297,-18055342,-6168792,-1984914,15707771,26342023,10146099 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -26016874,-219943,21339191,-41388,19745256,-2878700,-29637280,2227040,21612326,-545728 ), + new FieldElement( -13077387,1184228,23562814,-5970442,-20351244,-6348714,25764461,12243797,-20856566,11649658 ), + new FieldElement( -10031494,11262626,27384172,2271902,26947504,-15997771,39944,6114064,33514190,2333242 ) + ), + new GroupElementPreComp( + new FieldElement( -21433588,-12421821,8119782,7219913,-21830522,-9016134,-6679750,-12670638,24350578,-13450001 ), + new FieldElement( -4116307,-11271533,-23886186,4843615,-30088339,690623,-31536088,-10406836,8317860,12352766 ), + new FieldElement( 18200138,-14475911,-33087759,-2696619,-23702521,-9102511,-23552096,-2287550,20712163,6719373 ) + ), + new GroupElementPreComp( + new FieldElement( 26656208,6075253,-7858556,1886072,-28344043,4262326,11117530,-3763210,26224235,-3297458 ), + new FieldElement( -17168938,-14854097,-3395676,-16369877,-19954045,14050420,21728352,9493610,18620611,-16428628 ), + new FieldElement( -13323321,13325349,11432106,5964811,18609221,6062965,-5269471,-9725556,-30701573,-16479657 ) + ), + new GroupElementPreComp( + new FieldElement( -23860538,-11233159,26961357,1640861,-32413112,-16737940,12248509,-5240639,13735342,1934062 ), + new FieldElement( 25089769,6742589,17081145,-13406266,21909293,-16067981,-15136294,-3765346,-21277997,5473616 ), + new FieldElement( 31883677,-7961101,1083432,-11572403,22828471,13290673,-7125085,12469656,29111212,-5451014 ) + ), + new GroupElementPreComp( + new FieldElement( 24244947,-15050407,-26262976,2791540,-14997599,16666678,24367466,6388839,-10295587,452383 ), + new FieldElement( -25640782,-3417841,5217916,16224624,19987036,-4082269,-24236251,-5915248,15766062,8407814 ), + new FieldElement( -20406999,13990231,15495425,16395525,5377168,15166495,-8917023,-4388953,-8067909,2276718 ) + ), + new GroupElementPreComp( + new FieldElement( 30157918,12924066,-17712050,9245753,19895028,3368142,-23827587,5096219,22740376,-7303417 ), + new FieldElement( 2041139,-14256350,7783687,13876377,-25946985,-13352459,24051124,13742383,-15637599,13295222 ), + new FieldElement( 33338237,-8505733,12532113,7977527,9106186,-1715251,-17720195,-4612972,-4451357,-14669444 ) + ), + new GroupElementPreComp( + new FieldElement( -20045281,5454097,-14346548,6447146,28862071,1883651,-2469266,-4141880,7770569,9620597 ), + new FieldElement( 23208068,7979712,33071466,8149229,1758231,-10834995,30945528,-1694323,-33502340,-14767970 ), + new FieldElement( 1439958,-16270480,-1079989,-793782,4625402,10647766,-5043801,1220118,30494170,-11440799 ) + ), + new GroupElementPreComp( + new FieldElement( -5037580,-13028295,-2970559,-3061767,15640974,-6701666,-26739026,926050,-1684339,-13333647 ), + new FieldElement( 13908495,-3549272,30919928,-6273825,-21521863,7989039,9021034,9078865,3353509,4033511 ), + new FieldElement( -29663431,-15113610,32259991,-344482,24295849,-12912123,23161163,8839127,27485041,7356032 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 9661027,705443,11980065,-5370154,-1628543,14661173,-6346142,2625015,28431036,-16771834 ), + new FieldElement( -23839233,-8311415,-25945511,7480958,-17681669,-8354183,-22545972,14150565,15970762,4099461 ), + new FieldElement( 29262576,16756590,26350592,-8793563,8529671,-11208050,13617293,-9937143,11465739,8317062 ) + ), + new GroupElementPreComp( + new FieldElement( -25493081,-6962928,32500200,-9419051,-23038724,-2302222,14898637,3848455,20969334,-5157516 ), + new FieldElement( -20384450,-14347713,-18336405,13884722,-33039454,2842114,-21610826,-3649888,11177095,14989547 ), + new FieldElement( -24496721,-11716016,16959896,2278463,12066309,10137771,13515641,2581286,-28487508,9930240 ) + ), + new GroupElementPreComp( + new FieldElement( -17751622,-2097826,16544300,-13009300,-15914807,-14949081,18345767,-13403753,16291481,-5314038 ), + new FieldElement( -33229194,2553288,32678213,9875984,8534129,6889387,-9676774,6957617,4368891,9788741 ), + new FieldElement( 16660756,7281060,-10830758,12911820,20108584,-8101676,-21722536,-8613148,16250552,-11111103 ) + ), + new GroupElementPreComp( + new FieldElement( -19765507,2390526,-16551031,14161980,1905286,6414907,4689584,10604807,-30190403,4782747 ), + new FieldElement( -1354539,14736941,-7367442,-13292886,7710542,-14155590,-9981571,4383045,22546403,437323 ), + new FieldElement( 31665577,-12180464,-16186830,1491339,-18368625,3294682,27343084,2786261,-30633590,-14097016 ) + ), + new GroupElementPreComp( + new FieldElement( -14467279,-683715,-33374107,7448552,19294360,14334329,-19690631,2355319,-19284671,-6114373 ), + new FieldElement( 15121312,-15796162,6377020,-6031361,-10798111,-12957845,18952177,15496498,-29380133,11754228 ), + new FieldElement( -2637277,-13483075,8488727,-14303896,12728761,-1622493,7141596,11724556,22761615,-10134141 ) + ), + new GroupElementPreComp( + new FieldElement( 16918416,11729663,-18083579,3022987,-31015732,-13339659,-28741185,-12227393,32851222,11717399 ), + new FieldElement( 11166634,7338049,-6722523,4531520,-29468672,-7302055,31474879,3483633,-1193175,-4030831 ), + new FieldElement( -185635,9921305,31456609,-13536438,-12013818,13348923,33142652,6546660,-19985279,-3948376 ) + ), + new GroupElementPreComp( + new FieldElement( -32460596,11266712,-11197107,-7899103,31703694,3855903,-8537131,-12833048,-30772034,-15486313 ), + new FieldElement( -18006477,12709068,3991746,-6479188,-21491523,-10550425,-31135347,-16049879,10928917,3011958 ), + new FieldElement( -6957757,-15594337,31696059,334240,29576716,14796075,-30831056,-12805180,18008031,10258577 ) + ), + new GroupElementPreComp( + new FieldElement( -22448644,15655569,7018479,-4410003,-30314266,-1201591,-1853465,1367120,25127874,6671743 ), + new FieldElement( 29701166,-14373934,-10878120,9279288,-17568,13127210,21382910,11042292,25838796,4642684 ), + new FieldElement( -20430234,14955537,-24126347,8124619,-5369288,-5990470,30468147,-13900640,18423289,4177476 ) + ) + } + }; + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/base2.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/base2.cs new file mode 100644 index 000000000..c86de62a1 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/base2.cs @@ -0,0 +1,50 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class LookupTables + { + internal static readonly GroupElementPreComp[] Base2 = new GroupElementPreComp[]{ + new GroupElementPreComp( + new FieldElement( 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 ), + new FieldElement( -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 ), + new FieldElement( -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 ) + ), + new GroupElementPreComp( + new FieldElement( 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 ), + new FieldElement( 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 ), + new FieldElement( 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 ) + ), + new GroupElementPreComp( + new FieldElement( 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 ), + new FieldElement( 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 ), + new FieldElement( 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 ) + ), + new GroupElementPreComp( + new FieldElement( 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 ), + new FieldElement( -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 ), + new FieldElement( 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 ) + ), + new GroupElementPreComp( + new FieldElement( -22518993,-6692182,14201702,-8745502,-23510406,8844726,18474211,-1361450,-13062696,13821877 ), + new FieldElement( -6455177,-7839871,3374702,-4740862,-27098617,-10571707,31655028,-7212327,18853322,-14220951 ), + new FieldElement( 4566830,-12963868,-28974889,-12240689,-7602672,-2830569,-8514358,-10431137,2207753,-3209784 ) + ), + new GroupElementPreComp( + new FieldElement( -25154831,-4185821,29681144,7868801,-6854661,-9423865,-12437364,-663000,-31111463,-16132436 ), + new FieldElement( 25576264,-2703214,7349804,-11814844,16472782,9300885,3844789,15725684,171356,6466918 ), + new FieldElement( 23103977,13316479,9739013,-16149481,817875,-15038942,8965339,-14088058,-30714912,16193877 ) + ), + new GroupElementPreComp( + new FieldElement( -33521811,3180713,-2394130,14003687,-16903474,-16270840,17238398,4729455,-18074513,9256800 ), + new FieldElement( -25182317,-4174131,32336398,5036987,-21236817,11360617,22616405,9761698,-19827198,630305 ), + new FieldElement( -13720693,2639453,-24237460,-7406481,9494427,-5774029,-6554551,-15960994,-2449256,-14291300 ) + ), + new GroupElementPreComp( + new FieldElement( -3151181,-5046075,9282714,6866145,-31907062,-863023,-18940575,15033784,25105118,-7894876 ), + new FieldElement( -24326370,15950226,-31801215,-14592823,-11662737,-5090925,1573892,-2625887,2198790,-15804619 ), + new FieldElement( -3099351,10324967,-2241613,7453183,-5446979,-2735503,-13812022,-16236442,-32461234,-12290683 ) + ) + }; + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/d.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/d.cs new file mode 100644 index 000000000..b5a957307 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/d.cs @@ -0,0 +1,9 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class LookupTables + { + internal static FieldElement d = new FieldElement(-10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116); + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/d2.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/d2.cs new file mode 100644 index 000000000..5c6bb61e9 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/d2.cs @@ -0,0 +1,9 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class LookupTables + { + internal static FieldElement d2 = new FieldElement(-21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199); + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_0.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_0.cs new file mode 100644 index 000000000..632c1b942 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_0.cs @@ -0,0 +1,12 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + public static void fe_0(out FieldElement h) + { + h = default(FieldElement); + } + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_1.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_1.cs new file mode 100644 index 000000000..dfed794b5 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_1.cs @@ -0,0 +1,13 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + public static void fe_1(out FieldElement h) + { + h = default(FieldElement); + h.x0 = 1; + } + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_add.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_add.cs new file mode 100644 index 000000000..7eb6b9ff1 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_add.cs @@ -0,0 +1,64 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + h = f + g + Can overlap h with f or g. + + Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + + Postconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + */ + //void fe_add(fe h,const fe f,const fe g) + internal static void fe_add(out FieldElement h, ref FieldElement f, ref FieldElement g) + { + int f0 = f.x0; + int f1 = f.x1; + int f2 = f.x2; + int f3 = f.x3; + int f4 = f.x4; + int f5 = f.x5; + int f6 = f.x6; + int f7 = f.x7; + int f8 = f.x8; + int f9 = f.x9; + int g0 = g.x0; + int g1 = g.x1; + int g2 = g.x2; + int g3 = g.x3; + int g4 = g.x4; + int g5 = g.x5; + int g6 = g.x6; + int g7 = g.x7; + int g8 = g.x8; + int g9 = g.x9; + int h0 = f0 + g0; + int h1 = f1 + g1; + int h2 = f2 + g2; + int h3 = f3 + g3; + int h4 = f4 + g4; + int h5 = f5 + g5; + int h6 = f6 + g6; + int h7 = f7 + g7; + int h8 = f8 + g8; + int h9 = f9 + g9; + + h.x0 = h0; + h.x1 = h1; + h.x2 = h2; + h.x3 = h3; + h.x4 = h4; + h.x5 = h5; + h.x6 = h6; + h.x7 = h7; + h.x8 = h8; + h.x9 = h9; + } + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_cmov.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_cmov.cs new file mode 100644 index 000000000..765650694 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_cmov.cs @@ -0,0 +1,71 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + Replace (f,g) with (g,g) if b == 1; + replace (f,g) with (f,g) if b == 0. + + Preconditions: b in {0,1}. + */ + + //void fe_cmov(fe f,const fe g,unsigned int b) + internal static void fe_cmov(ref FieldElement f, ref FieldElement g, int b) + { + int f0 = f.x0; + int f1 = f.x1; + int f2 = f.x2; + int f3 = f.x3; + int f4 = f.x4; + int f5 = f.x5; + int f6 = f.x6; + int f7 = f.x7; + int f8 = f.x8; + int f9 = f.x9; + int g0 = g.x0; + int g1 = g.x1; + int g2 = g.x2; + int g3 = g.x3; + int g4 = g.x4; + int g5 = g.x5; + int g6 = g.x6; + int g7 = g.x7; + int g8 = g.x8; + int g9 = g.x9; + int x0 = f0 ^ g0; + int x1 = f1 ^ g1; + int x2 = f2 ^ g2; + int x3 = f3 ^ g3; + int x4 = f4 ^ g4; + int x5 = f5 ^ g5; + int x6 = f6 ^ g6; + int x7 = f7 ^ g7; + int x8 = f8 ^ g8; + int x9 = f9 ^ g9; + + b = -b; + x0 &= b; + x1 &= b; + x2 &= b; + x3 &= b; + x4 &= b; + x5 &= b; + x6 &= b; + x7 &= b; + x8 &= b; + x9 &= b; + f.x0 = f0 ^ x0; + f.x1 = f1 ^ x1; + f.x2 = f2 ^ x2; + f.x3 = f3 ^ x3; + f.x4 = f4 ^ x4; + f.x5 = f5 ^ x5; + f.x6 = f6 ^ x6; + f.x7 = f7 ^ x7; + f.x8 = f8 ^ x8; + f.x9 = f9 ^ x9; + } + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_cswap.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_cswap.cs new file mode 100644 index 000000000..50815dbfa --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_cswap.cs @@ -0,0 +1,79 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + Replace (f,g) with (g,f) if b == 1; + replace (f,g) with (f,g) if b == 0. + + Preconditions: b in {0,1}. + */ + public static void fe_cswap(ref FieldElement f, ref FieldElement g, uint b) + { + int f0 = f.x0; + int f1 = f.x1; + int f2 = f.x2; + int f3 = f.x3; + int f4 = f.x4; + int f5 = f.x5; + int f6 = f.x6; + int f7 = f.x7; + int f8 = f.x8; + int f9 = f.x9; + int g0 = g.x0; + int g1 = g.x1; + int g2 = g.x2; + int g3 = g.x3; + int g4 = g.x4; + int g5 = g.x5; + int g6 = g.x6; + int g7 = g.x7; + int g8 = g.x8; + int g9 = g.x9; + int x0 = f0 ^ g0; + int x1 = f1 ^ g1; + int x2 = f2 ^ g2; + int x3 = f3 ^ g3; + int x4 = f4 ^ g4; + int x5 = f5 ^ g5; + int x6 = f6 ^ g6; + int x7 = f7 ^ g7; + int x8 = f8 ^ g8; + int x9 = f9 ^ g9; + + int negb = unchecked((int)-b); + x0 &= negb; + x1 &= negb; + x2 &= negb; + x3 &= negb; + x4 &= negb; + x5 &= negb; + x6 &= negb; + x7 &= negb; + x8 &= negb; + x9 &= negb; + f.x0 = f0 ^ x0; + f.x1 = f1 ^ x1; + f.x2 = f2 ^ x2; + f.x3 = f3 ^ x3; + f.x4 = f4 ^ x4; + f.x5 = f5 ^ x5; + f.x6 = f6 ^ x6; + f.x7 = f7 ^ x7; + f.x8 = f8 ^ x8; + f.x9 = f9 ^ x9; + g.x0 = g0 ^ x0; + g.x1 = g1 ^ x1; + g.x2 = g2 ^ x2; + g.x3 = g3 ^ x3; + g.x4 = g4 ^ x4; + g.x5 = g5 ^ x5; + g.x6 = g6 ^ x6; + g.x7 = g7 ^ x7; + g.x8 = g8 ^ x8; + g.x9 = g9 ^ x9; + } + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_frombytes.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_frombytes.cs new file mode 100644 index 000000000..3689ff952 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_frombytes.cs @@ -0,0 +1,102 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + private static long load_3(byte[] data, int offset) + { + uint result; + result = data[offset + 0]; + result |= (uint)data[offset + 1] << 8; + result |= (uint)data[offset + 2] << 16; + return (long)(ulong)result; + } + + private static long load_4(byte[] data, int offset) + { + uint result; + result = data[offset + 0]; + result |= (uint)data[offset + 1] << 8; + result |= (uint)data[offset + 2] << 16; + result |= (uint)data[offset + 3] << 24; + return (long)(ulong)result; + } + + // Ignores top bit of h. + internal static void fe_frombytes(out FieldElement h, byte[] data, int offset) + { + var h0 = load_4(data, offset); + var h1 = load_3(data, offset + 4) << 6; + var h2 = load_3(data, offset + 7) << 5; + var h3 = load_3(data, offset + 10) << 3; + var h4 = load_3(data, offset + 13) << 2; + var h5 = load_4(data, offset + 16); + var h6 = load_3(data, offset + 20) << 7; + var h7 = load_3(data, offset + 23) << 5; + var h8 = load_3(data, offset + 26) << 4; + var h9 = (load_3(data, offset + 29) & 8388607) << 2; + + var carry9 = (h9 + (1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + var carry1 = (h1 + (1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + var carry3 = (h3 + (1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + var carry5 = (h5 + (1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + var carry7 = (h7 + (1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + var carry0 = (h0 + (1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + var carry2 = (h2 + (1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + var carry4 = (h4 + (1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + var carry6 = (h6 + (1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + var carry8 = (h8 + (1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + h.x0 = (int)h0; + h.x1 = (int)h1; + h.x2 = (int)h2; + h.x3 = (int)h3; + h.x4 = (int)h4; + h.x5 = (int)h5; + h.x6 = (int)h6; + h.x7 = (int)h7; + h.x8 = (int)h8; + h.x9 = (int)h9; + } + + // does NOT ignore top bit + internal static void fe_frombytes2(out FieldElement h, byte[] data, int offset) + { + var h0 = load_4(data, offset); + var h1 = load_3(data, offset + 4) << 6; + var h2 = load_3(data, offset + 7) << 5; + var h3 = load_3(data, offset + 10) << 3; + var h4 = load_3(data, offset + 13) << 2; + var h5 = load_4(data, offset + 16); + var h6 = load_3(data, offset + 20) << 7; + var h7 = load_3(data, offset + 23) << 5; + var h8 = load_3(data, offset + 26) << 4; + var h9 = load_3(data, offset + 29) << 2; + + var carry9 = (h9 + (1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + var carry1 = (h1 + (1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + var carry3 = (h3 + (1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + var carry5 = (h5 + (1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + var carry7 = (h7 + (1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + var carry0 = (h0 + (1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + var carry2 = (h2 + (1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + var carry4 = (h4 + (1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + var carry6 = (h6 + (1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + var carry8 = (h8 + (1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + h.x0 = (int)h0; + h.x1 = (int)h1; + h.x2 = (int)h2; + h.x3 = (int)h3; + h.x4 = (int)h4; + h.x5 = (int)h5; + h.x6 = (int)h6; + h.x7 = (int)h7; + h.x8 = (int)h8; + h.x9 = (int)h9; + } + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_invert.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_invert.cs new file mode 100644 index 000000000..943133e07 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_invert.cs @@ -0,0 +1,128 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + internal static void fe_invert(out FieldElement result, ref FieldElement z) + { + FieldElement t0, t1, t2, t3; + int i; + + /* qhasm: z2 = z1^2^1 */ + /* asm 1: fe_sq(>z2=fe#1,z2=fe#1,>z2=fe#1); */ + /* asm 2: fe_sq(>z2=t0,z2=t0,>z2=t0); */ + fe_sq(out t0, ref z); //for (i = 1; i < 1; ++i) fe_sq(out t0, ref t0); + + /* qhasm: z8 = z2^2^2 */ + /* asm 1: fe_sq(>z8=fe#2,z8=fe#2,>z8=fe#2); */ + /* asm 2: fe_sq(>z8=t1,z8=t1,>z8=t1); */ + fe_sq(out t1, ref t0); for (i = 1; i < 2; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z9 = z1*z8 */ + /* asm 1: fe_mul(>z9=fe#2,z9=t1,z11=fe#1,z11=t0,z22=fe#3,z22=fe#3,>z22=fe#3); */ + /* asm 2: fe_sq(>z22=t2,z22=t2,>z22=t2); */ + fe_sq(out t2, ref t0); //for (i = 1; i < 1; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_5_0 = z9*z22 */ + /* asm 1: fe_mul(>z_5_0=fe#2,z_5_0=t1,z_10_5=fe#3,z_10_5=fe#3,>z_10_5=fe#3); */ + /* asm 2: fe_sq(>z_10_5=t2,z_10_5=t2,>z_10_5=t2); */ + fe_sq(out t2, ref t1); for (i = 1; i < 5; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_10_0 = z_10_5*z_5_0 */ + /* asm 1: fe_mul(>z_10_0=fe#2,z_10_0=t1,z_20_10=fe#3,z_20_10=fe#3,>z_20_10=fe#3); */ + /* asm 2: fe_sq(>z_20_10=t2,z_20_10=t2,>z_20_10=t2); */ + fe_sq(out t2, ref t1); for (i = 1; i < 10; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_20_0 = z_20_10*z_10_0 */ + /* asm 1: fe_mul(>z_20_0=fe#3,z_20_0=t2,z_40_20=fe#4,z_40_20=fe#4,>z_40_20=fe#4); */ + /* asm 2: fe_sq(>z_40_20=t3,z_40_20=t3,>z_40_20=t3); */ + fe_sq(out t3, ref t2); for (i = 1; i < 20; ++i) fe_sq(out t3, ref t3); + + /* qhasm: z_40_0 = z_40_20*z_20_0 */ + /* asm 1: fe_mul(>z_40_0=fe#3,z_40_0=t2,z_50_10=fe#3,z_50_10=fe#3,>z_50_10=fe#3); */ + /* asm 2: fe_sq(>z_50_10=t2,z_50_10=t2,>z_50_10=t2); */ + fe_sq(out t2, ref t2); for (i = 1; i < 10; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_50_0 = z_50_10*z_10_0 */ + /* asm 1: fe_mul(>z_50_0=fe#2,z_50_0=t1,z_100_50=fe#3,z_100_50=fe#3,>z_100_50=fe#3); */ + /* asm 2: fe_sq(>z_100_50=t2,z_100_50=t2,>z_100_50=t2); */ + fe_sq(out t2, ref t1); for (i = 1; i < 50; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_100_0 = z_100_50*z_50_0 */ + /* asm 1: fe_mul(>z_100_0=fe#3,z_100_0=t2,z_200_100=fe#4,z_200_100=fe#4,>z_200_100=fe#4); */ + /* asm 2: fe_sq(>z_200_100=t3,z_200_100=t3,>z_200_100=t3); */ + fe_sq(out t3, ref t2); for (i = 1; i < 100; ++i) fe_sq(out t3, ref t3); + + /* qhasm: z_200_0 = z_200_100*z_100_0 */ + /* asm 1: fe_mul(>z_200_0=fe#3,z_200_0=t2,z_250_50=fe#3,z_250_50=fe#3,>z_250_50=fe#3); */ + /* asm 2: fe_sq(>z_250_50=t2,z_250_50=t2,>z_250_50=t2); */ + fe_sq(out t2, ref t2); for (i = 1; i < 50; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_250_0 = z_250_50*z_50_0 */ + /* asm 1: fe_mul(>z_250_0=fe#2,z_250_0=t1,z_255_5=fe#2,z_255_5=fe#2,>z_255_5=fe#2); */ + /* asm 2: fe_sq(>z_255_5=t1,z_255_5=t1,>z_255_5=t1); */ + fe_sq(out t1, ref t1); for (i = 1; i < 5; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z_255_21 = z_255_5*z11 */ + /* asm 1: fe_mul(>z_255_21=fe#12,z_255_21=out,> 31) ^ 1); + } + } +} \ No newline at end of file diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_mul.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_mul.cs new file mode 100644 index 000000000..4774cd5d5 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_mul.cs @@ -0,0 +1,263 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + h = f * g + Can overlap h with f or g. + + Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + + Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. + */ + + /* + Notes on implementation strategy: + + Using schoolbook multiplication. + Karatsuba would save a little in some cost models. + + Most multiplications by 2 and 19 are 32-bit precomputations; + cheaper than 64-bit postcomputations. + + There is one remaining multiplication by 19 in the carry chain; + one *19 precomputation can be merged into this, + but the resulting data flow is considerably less clean. + + There are 12 carries below. + 10 of them are 2-way parallelizable and vectorizable. + Can get away with 11 carries, but then data flow is much deeper. + + With tighter constraints on inputs can squeeze carries into int32. + */ + + internal static void fe_mul(out FieldElement h, ref FieldElement f, ref FieldElement g) + { + int f0 = f.x0; + int f1 = f.x1; + int f2 = f.x2; + int f3 = f.x3; + int f4 = f.x4; + int f5 = f.x5; + int f6 = f.x6; + int f7 = f.x7; + int f8 = f.x8; + int f9 = f.x9; + int g0 = g.x0; + int g1 = g.x1; + int g2 = g.x2; + int g3 = g.x3; + int g4 = g.x4; + int g5 = g.x5; + int g6 = g.x6; + int g7 = g.x7; + int g8 = g.x8; + int g9 = g.x9; + + int g1_19 = 19 * g1; /* 1.959375*2^29 */ + int g2_19 = 19 * g2; /* 1.959375*2^30; still ok */ + int g3_19 = 19 * g3; + int g4_19 = 19 * g4; + int g5_19 = 19 * g5; + int g6_19 = 19 * g6; + int g7_19 = 19 * g7; + int g8_19 = 19 * g8; + int g9_19 = 19 * g9; + + int f1_2 = 2 * f1; + int f3_2 = 2 * f3; + int f5_2 = 2 * f5; + int f7_2 = 2 * f7; + int f9_2 = 2 * f9; + + long f0g0 = f0 * (long)g0; + long f0g1 = f0 * (long)g1; + long f0g2 = f0 * (long)g2; + long f0g3 = f0 * (long)g3; + long f0g4 = f0 * (long)g4; + long f0g5 = f0 * (long)g5; + long f0g6 = f0 * (long)g6; + long f0g7 = f0 * (long)g7; + long f0g8 = f0 * (long)g8; + long f0g9 = f0 * (long)g9; + long f1g0 = f1 * (long)g0; + long f1g1_2 = f1_2 * (long)g1; + long f1g2 = f1 * (long)g2; + long f1g3_2 = f1_2 * (long)g3; + long f1g4 = f1 * (long)g4; + long f1g5_2 = f1_2 * (long)g5; + long f1g6 = f1 * (long)g6; + long f1g7_2 = f1_2 * (long)g7; + long f1g8 = f1 * (long)g8; + long f1g9_38 = f1_2 * (long)g9_19; + long f2g0 = f2 * (long)g0; + long f2g1 = f2 * (long)g1; + long f2g2 = f2 * (long)g2; + long f2g3 = f2 * (long)g3; + long f2g4 = f2 * (long)g4; + long f2g5 = f2 * (long)g5; + long f2g6 = f2 * (long)g6; + long f2g7 = f2 * (long)g7; + long f2g8_19 = f2 * (long)g8_19; + long f2g9_19 = f2 * (long)g9_19; + long f3g0 = f3 * (long)g0; + long f3g1_2 = f3_2 * (long)g1; + long f3g2 = f3 * (long)g2; + long f3g3_2 = f3_2 * (long)g3; + long f3g4 = f3 * (long)g4; + long f3g5_2 = f3_2 * (long)g5; + long f3g6 = f3 * (long)g6; + long f3g7_38 = f3_2 * (long)g7_19; + long f3g8_19 = f3 * (long)g8_19; + long f3g9_38 = f3_2 * (long)g9_19; + long f4g0 = f4 * (long)g0; + long f4g1 = f4 * (long)g1; + long f4g2 = f4 * (long)g2; + long f4g3 = f4 * (long)g3; + long f4g4 = f4 * (long)g4; + long f4g5 = f4 * (long)g5; + long f4g6_19 = f4 * (long)g6_19; + long f4g7_19 = f4 * (long)g7_19; + long f4g8_19 = f4 * (long)g8_19; + long f4g9_19 = f4 * (long)g9_19; + long f5g0 = f5 * (long)g0; + long f5g1_2 = f5_2 * (long)g1; + long f5g2 = f5 * (long)g2; + long f5g3_2 = f5_2 * (long)g3; + long f5g4 = f5 * (long)g4; + long f5g5_38 = f5_2 * (long)g5_19; + long f5g6_19 = f5 * (long)g6_19; + long f5g7_38 = f5_2 * (long)g7_19; + long f5g8_19 = f5 * (long)g8_19; + long f5g9_38 = f5_2 * (long)g9_19; + long f6g0 = f6 * (long)g0; + long f6g1 = f6 * (long)g1; + long f6g2 = f6 * (long)g2; + long f6g3 = f6 * (long)g3; + long f6g4_19 = f6 * (long)g4_19; + long f6g5_19 = f6 * (long)g5_19; + long f6g6_19 = f6 * (long)g6_19; + long f6g7_19 = f6 * (long)g7_19; + long f6g8_19 = f6 * (long)g8_19; + long f6g9_19 = f6 * (long)g9_19; + long f7g0 = f7 * (long)g0; + long f7g1_2 = f7_2 * (long)g1; + long f7g2 = f7 * (long)g2; + long f7g3_38 = f7_2 * (long)g3_19; + long f7g4_19 = f7 * (long)g4_19; + long f7g5_38 = f7_2 * (long)g5_19; + long f7g6_19 = f7 * (long)g6_19; + long f7g7_38 = f7_2 * (long)g7_19; + long f7g8_19 = f7 * (long)g8_19; + long f7g9_38 = f7_2 * (long)g9_19; + long f8g0 = f8 * (long)g0; + long f8g1 = f8 * (long)g1; + long f8g2_19 = f8 * (long)g2_19; + long f8g3_19 = f8 * (long)g3_19; + long f8g4_19 = f8 * (long)g4_19; + long f8g5_19 = f8 * (long)g5_19; + long f8g6_19 = f8 * (long)g6_19; + long f8g7_19 = f8 * (long)g7_19; + long f8g8_19 = f8 * (long)g8_19; + long f8g9_19 = f8 * (long)g9_19; + long f9g0 = f9 * (long)g0; + long f9g1_38 = f9_2 * (long)g1_19; + long f9g2_19 = f9 * (long)g2_19; + long f9g3_38 = f9_2 * (long)g3_19; + long f9g4_19 = f9 * (long)g4_19; + long f9g5_38 = f9_2 * (long)g5_19; + long f9g6_19 = f9 * (long)g6_19; + long f9g7_38 = f9_2 * (long)g7_19; + long f9g8_19 = f9 * (long)g8_19; + long f9g9_38 = f9_2 * (long)g9_19; + + long h0 = f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38; + long h1 = f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19; + long h2 = f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38; + long h3 = f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19; + long h4 = f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38; + long h5 = f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19; + long h6 = f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38; + long h7 = f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19; + long h8 = f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38; + long h9 = f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0; + + long carry0; + long carry1; + long carry2; + long carry3; + long carry4; + long carry5; + long carry6; + long carry7; + long carry8; + long carry9; + + /* + |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38)) + i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8 + |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19)) + i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 + */ + + carry0 = (h0 + (long)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry4 = (h4 + (long)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + /* |h0| <= 2^25 */ + /* |h4| <= 2^25 */ + /* |h1| <= 1.71*2^59 */ + /* |h5| <= 1.71*2^59 */ + + carry1 = (h1 + (long)(1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry5 = (h5 + (long)(1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + /* |h1| <= 2^24; from now on fits into int32 */ + /* |h5| <= 2^24; from now on fits into int32 */ + /* |h2| <= 1.41*2^60 */ + /* |h6| <= 1.41*2^60 */ + + carry2 = (h2 + (long)(1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry6 = (h6 + (long)(1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + /* |h2| <= 2^25; from now on fits into int32 unchanged */ + /* |h6| <= 2^25; from now on fits into int32 unchanged */ + /* |h3| <= 1.71*2^59 */ + /* |h7| <= 1.71*2^59 */ + + carry3 = (h3 + (long)(1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry7 = (h7 + (long)(1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + /* |h3| <= 2^24; from now on fits into int32 unchanged */ + /* |h7| <= 2^24; from now on fits into int32 unchanged */ + /* |h4| <= 1.72*2^34 */ + /* |h8| <= 1.41*2^60 */ + + carry4 = (h4 + (long)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry8 = (h8 + (long)(1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + /* |h4| <= 2^25; from now on fits into int32 unchanged */ + /* |h8| <= 2^25; from now on fits into int32 unchanged */ + /* |h5| <= 1.01*2^24 */ + /* |h9| <= 1.71*2^59 */ + + carry9 = (h9 + (long)(1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + /* |h9| <= 2^24; from now on fits into int32 unchanged */ + /* |h0| <= 1.1*2^39 */ + + carry0 = (h0 + (long)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + /* |h0| <= 2^25; from now on fits into int32 unchanged */ + /* |h1| <= 1.01*2^24 */ + + h.x0 = (int)h0; + h.x1 = (int)h1; + h.x2 = (int)h2; + h.x3 = (int)h3; + h.x4 = (int)h4; + h.x5 = (int)h5; + h.x6 = (int)h6; + h.x7 = (int)h7; + h.x8 = (int)h8; + h.x9 = (int)h9; + } + } +} \ No newline at end of file diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_mul121666.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_mul121666.cs new file mode 100644 index 000000000..2bbd3f688 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_mul121666.cs @@ -0,0 +1,67 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + + /* + h = f * 121666 + Can overlap h with f. + + Preconditions: + |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + + Postconditions: + |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + */ + + public static void fe_mul121666(out FieldElement h, ref FieldElement f) + { + int f0 = f.x0; + int f1 = f.x1; + int f2 = f.x2; + int f3 = f.x3; + int f4 = f.x4; + int f5 = f.x5; + int f6 = f.x6; + int f7 = f.x7; + int f8 = f.x8; + int f9 = f.x9; + + var h0 = f0 * 121666L; + var h1 = f1 * 121666L; + var h2 = f2 * 121666L; + var h3 = f3 * 121666L; + var h4 = f4 * 121666L; + var h5 = f5 * 121666L; + var h6 = f6 * 121666L; + var h7 = f7 * 121666L; + var h8 = f8 * 121666L; + var h9 = f9 * 121666L; + + var carry9 = (h9 + (1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + var carry1 = (h1 + (1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + var carry3 = (h3 + (1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + var carry5 = (h5 + (1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + var carry7 = (h7 + (1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + var carry0 = (h0 + (1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + var carry2 = (h2 + (1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + var carry4 = (h4 + (1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + var carry6 = (h6 + (1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + var carry8 = (h8 + (1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + h.x0 = (int)h0; + h.x1 = (int)h1; + h.x2 = (int)h2; + h.x3 = (int)h3; + h.x4 = (int)h4; + h.x5 = (int)h5; + h.x6 = (int)h6; + h.x7 = (int)h7; + h.x8 = (int)h8; + h.x9 = (int)h9; + } + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_neg.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_neg.cs new file mode 100644 index 000000000..9b3d18139 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_neg.cs @@ -0,0 +1,51 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + h = -f + + Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + + Postconditions: + |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + */ + internal static void fe_neg(out FieldElement h, ref FieldElement f) + { + int f0 = f.x0; + int f1 = f.x1; + int f2 = f.x2; + int f3 = f.x3; + int f4 = f.x4; + int f5 = f.x5; + int f6 = f.x6; + int f7 = f.x7; + int f8 = f.x8; + int f9 = f.x9; + int h0 = -f0; + int h1 = -f1; + int h2 = -f2; + int h3 = -f3; + int h4 = -f4; + int h5 = -f5; + int h6 = -f6; + int h7 = -f7; + int h8 = -f8; + int h9 = -f9; + + h.x0 = h0; + h.x1 = h1; + h.x2 = h2; + h.x3 = h3; + h.x4 = h4; + h.x5 = h5; + h.x6 = h6; + h.x7 = h7; + h.x8 = h8; + h.x9 = h9; + } + } +} \ No newline at end of file diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_pow22523.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_pow22523.cs new file mode 100644 index 000000000..63bb33b59 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_pow22523.cs @@ -0,0 +1,125 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + internal static void fe_pow22523(out FieldElement result, ref FieldElement z) + { + FieldElement t0, t1, t2; + int i; + + /* qhasm: z2 = z1^2^1 */ + /* asm 1: fe_sq(>z2=fe#1,z2=fe#1,>z2=fe#1); */ + /* asm 2: fe_sq(>z2=t0,z2=t0,>z2=t0); */ + fe_sq(out t0, ref z); //for (i = 1; i < 1; ++i) fe_sq(out t0, ref t0); + + /* qhasm: z8 = z2^2^2 */ + /* asm 1: fe_sq(>z8=fe#2,z8=fe#2,>z8=fe#2); */ + /* asm 2: fe_sq(>z8=t1,z8=t1,>z8=t1); */ + fe_sq(out t1, ref t0); for (i = 1; i < 2; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z9 = z1*z8 */ + /* asm 1: fe_mul(>z9=fe#2,z9=t1,z11=fe#1,z11=t0,z22=fe#1,z22=fe#1,>z22=fe#1); */ + /* asm 2: fe_sq(>z22=t0,z22=t0,>z22=t0); */ + fe_sq(out t0, ref t0); //for (i = 1; i < 1; ++i) fe_sq(out t0, ref t0); + + /* qhasm: z_5_0 = z9*z22 */ + /* asm 1: fe_mul(>z_5_0=fe#1,z_5_0=t0,z_10_5=fe#2,z_10_5=fe#2,>z_10_5=fe#2); */ + /* asm 2: fe_sq(>z_10_5=t1,z_10_5=t1,>z_10_5=t1); */ + fe_sq(out t1, ref t0); for (i = 1; i < 5; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z_10_0 = z_10_5*z_5_0 */ + /* asm 1: fe_mul(>z_10_0=fe#1,z_10_0=t0,z_20_10=fe#2,z_20_10=fe#2,>z_20_10=fe#2); */ + /* asm 2: fe_sq(>z_20_10=t1,z_20_10=t1,>z_20_10=t1); */ + fe_sq(out t1, ref t0); for (i = 1; i < 10; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z_20_0 = z_20_10*z_10_0 */ + /* asm 1: fe_mul(>z_20_0=fe#2,z_20_0=t1,z_40_20=fe#3,z_40_20=fe#3,>z_40_20=fe#3); */ + /* asm 2: fe_sq(>z_40_20=t2,z_40_20=t2,>z_40_20=t2); */ + fe_sq(out t2, ref t1); for (i = 1; i < 20; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_40_0 = z_40_20*z_20_0 */ + /* asm 1: fe_mul(>z_40_0=fe#2,z_40_0=t1,z_50_10=fe#2,z_50_10=fe#2,>z_50_10=fe#2); */ + /* asm 2: fe_sq(>z_50_10=t1,z_50_10=t1,>z_50_10=t1); */ + fe_sq(out t1, ref t1); for (i = 1; i < 10; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z_50_0 = z_50_10*z_10_0 */ + /* asm 1: fe_mul(>z_50_0=fe#1,z_50_0=t0,z_100_50=fe#2,z_100_50=fe#2,>z_100_50=fe#2); */ + /* asm 2: fe_sq(>z_100_50=t1,z_100_50=t1,>z_100_50=t1); */ + fe_sq(out t1, ref t0); for (i = 1; i < 50; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z_100_0 = z_100_50*z_50_0 */ + /* asm 1: fe_mul(>z_100_0=fe#2,z_100_0=t1,z_200_100=fe#3,z_200_100=fe#3,>z_200_100=fe#3); */ + /* asm 2: fe_sq(>z_200_100=t2,z_200_100=t2,>z_200_100=t2); */ + fe_sq(out t2, ref t1); for (i = 1; i < 100; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_200_0 = z_200_100*z_100_0 */ + /* asm 1: fe_mul(>z_200_0=fe#2,z_200_0=t1,z_250_50=fe#2,z_250_50=fe#2,>z_250_50=fe#2); */ + /* asm 2: fe_sq(>z_250_50=t1,z_250_50=t1,>z_250_50=t1); */ + fe_sq(out t1, ref t1); for (i = 1; i < 50; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z_250_0 = z_250_50*z_50_0 */ + /* asm 1: fe_mul(>z_250_0=fe#1,z_250_0=t0,z_252_2=fe#1,z_252_2=fe#1,>z_252_2=fe#1); */ + /* asm 2: fe_sq(>z_252_2=t0,z_252_2=t0,>z_252_2=t0); */ + fe_sq(out t0, ref t0); for (i = 1; i < 2; ++i) fe_sq(out t0, ref t0); + + /* qhasm: z_252_3 = z_252_2*z1 */ + /* asm 1: fe_mul(>z_252_3=fe#12,z_252_3=out,> 26; h1 += carry0; h0 -= carry0 << 26; + var carry4 = (h4 + (1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + var carry1 = (h1 + (1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + var carry5 = (h5 + (1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + var carry2 = (h2 + (1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + var carry6 = (h6 + (1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + var carry3 = (h3 + (1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + var carry7 = (h7 + (1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry4 = (h4 + (1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + + var carry8 = (h8 + (1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + var carry9 = (h9 + (1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + + carry0 = (h0 + (1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + + h.x0 = (int)h0; + h.x1 = (int)h1; + h.x2 = (int)h2; + h.x3 = (int)h3; + h.x4 = (int)h4; + h.x5 = (int)h5; + h.x6 = (int)h6; + h.x7 = (int)h7; + h.x8 = (int)h8; + h.x9 = (int)h9; + } + } +} \ No newline at end of file diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_sq2.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_sq2.cs new file mode 100644 index 000000000..d1c2ee33d --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_sq2.cs @@ -0,0 +1,154 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* +h = 2 * f * f +Can overlap h with f. + +Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + +Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. +*/ + + /* + See fe_mul.c for discussion of implementation strategy. + */ + internal static void fe_sq2(out FieldElement h, ref FieldElement f) + { + int f0 = f.x0; + int f1 = f.x1; + int f2 = f.x2; + int f3 = f.x3; + int f4 = f.x4; + int f5 = f.x5; + int f6 = f.x6; + int f7 = f.x7; + int f8 = f.x8; + int f9 = f.x9; + + int f0_2 = 2 * f0; + int f1_2 = 2 * f1; + int f2_2 = 2 * f2; + int f3_2 = 2 * f3; + int f4_2 = 2 * f4; + int f5_2 = 2 * f5; + int f6_2 = 2 * f6; + int f7_2 = 2 * f7; + int f5_38 = 38 * f5; /* 1.959375*2^30 */ + int f6_19 = 19 * f6; /* 1.959375*2^30 */ + int f7_38 = 38 * f7; /* 1.959375*2^30 */ + int f8_19 = 19 * f8; /* 1.959375*2^30 */ + int f9_38 = 38 * f9; /* 1.959375*2^30 */ + + var f0f0 = f0 * (long)f0; + var f0f1_2 = f0_2 * (long)f1; + var f0f2_2 = f0_2 * (long)f2; + var f0f3_2 = f0_2 * (long)f3; + var f0f4_2 = f0_2 * (long)f4; + var f0f5_2 = f0_2 * (long)f5; + var f0f6_2 = f0_2 * (long)f6; + var f0f7_2 = f0_2 * (long)f7; + var f0f8_2 = f0_2 * (long)f8; + var f0f9_2 = f0_2 * (long)f9; + var f1f1_2 = f1_2 * (long)f1; + var f1f2_2 = f1_2 * (long)f2; + var f1f3_4 = f1_2 * (long)f3_2; + var f1f4_2 = f1_2 * (long)f4; + var f1f5_4 = f1_2 * (long)f5_2; + var f1f6_2 = f1_2 * (long)f6; + var f1f7_4 = f1_2 * (long)f7_2; + var f1f8_2 = f1_2 * (long)f8; + var f1f9_76 = f1_2 * (long)f9_38; + var f2f2 = f2 * (long)f2; + var f2f3_2 = f2_2 * (long)f3; + var f2f4_2 = f2_2 * (long)f4; + var f2f5_2 = f2_2 * (long)f5; + var f2f6_2 = f2_2 * (long)f6; + var f2f7_2 = f2_2 * (long)f7; + var f2f8_38 = f2_2 * (long)f8_19; + var f2f9_38 = f2 * (long)f9_38; + var f3f3_2 = f3_2 * (long)f3; + var f3f4_2 = f3_2 * (long)f4; + var f3f5_4 = f3_2 * (long)f5_2; + var f3f6_2 = f3_2 * (long)f6; + var f3f7_76 = f3_2 * (long)f7_38; + var f3f8_38 = f3_2 * (long)f8_19; + var f3f9_76 = f3_2 * (long)f9_38; + var f4f4 = f4 * (long)f4; + var f4f5_2 = f4_2 * (long)f5; + var f4f6_38 = f4_2 * (long)f6_19; + var f4f7_38 = f4 * (long)f7_38; + var f4f8_38 = f4_2 * (long)f8_19; + var f4f9_38 = f4 * (long)f9_38; + var f5f5_38 = f5 * (long)f5_38; + var f5f6_38 = f5_2 * (long)f6_19; + var f5f7_76 = f5_2 * (long)f7_38; + var f5f8_38 = f5_2 * (long)f8_19; + var f5f9_76 = f5_2 * (long)f9_38; + var f6f6_19 = f6 * (long)f6_19; + var f6f7_38 = f6 * (long)f7_38; + var f6f8_38 = f6_2 * (long)f8_19; + var f6f9_38 = f6 * (long)f9_38; + var f7f7_38 = f7 * (long)f7_38; + var f7f8_38 = f7_2 * (long)f8_19; + var f7f9_76 = f7_2 * (long)f9_38; + var f8f8_19 = f8 * (long)f8_19; + var f8f9_38 = f8 * (long)f9_38; + var f9f9_38 = f9 * (long)f9_38; + + var h0 = f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38; + var h1 = f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38; + var h2 = f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19; + var h3 = f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38; + var h4 = f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38; + var h5 = f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38; + var h6 = f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19; + var h7 = f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38; + var h8 = f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38; + var h9 = f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2; + + h0 += h0; + h1 += h1; + h2 += h2; + h3 += h3; + h4 += h4; + h5 += h5; + h6 += h6; + h7 += h7; + h8 += h8; + h9 += h9; + + var carry0 = (h0 + (1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + var carry4 = (h4 + (1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + var carry1 = (h1 + (1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + var carry5 = (h5 + (1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + var carry2 = (h2 + (1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + var carry6 = (h6 + (1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + var carry3 = (h3 + (1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + var carry7 = (h7 + (1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry4 = (h4 + (1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + + var carry8 = (h8 + (1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + var carry9 = (h9 + (1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + + carry0 = (h0 + (1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + + h.x0 = (int)h0; + h.x1 = (int)h1; + h.x2 = (int)h2; + h.x3 = (int)h3; + h.x4 = (int)h4; + h.x5 = (int)h5; + h.x6 = (int)h6; + h.x7 = (int)h7; + h.x8 = (int)h8; + h.x9 = (int)h9; + } + } +} \ No newline at end of file diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_sub.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_sub.cs new file mode 100644 index 000000000..f76e6d752 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_sub.cs @@ -0,0 +1,66 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + h = f - g + Can overlap h with f or g. + + Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + + Postconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + */ + + internal static void fe_sub(out FieldElement h, ref FieldElement f, ref FieldElement g) + { + int f0 = f.x0; + int f1 = f.x1; + int f2 = f.x2; + int f3 = f.x3; + int f4 = f.x4; + int f5 = f.x5; + int f6 = f.x6; + int f7 = f.x7; + int f8 = f.x8; + int f9 = f.x9; + + int g0 = g.x0; + int g1 = g.x1; + int g2 = g.x2; + int g3 = g.x3; + int g4 = g.x4; + int g5 = g.x5; + int g6 = g.x6; + int g7 = g.x7; + int g8 = g.x8; + int g9 = g.x9; + + int h0 = f0 - g0; + int h1 = f1 - g1; + int h2 = f2 - g2; + int h3 = f3 - g3; + int h4 = f4 - g4; + int h5 = f5 - g5; + int h6 = f6 - g6; + int h7 = f7 - g7; + int h8 = f8 - g8; + int h9 = f9 - g9; + + h.x0 = h0; + h.x1 = h1; + h.x2 = h2; + h.x3 = h3; + h.x4 = h4; + h.x5 = h5; + h.x6 = h6; + h.x7 = h7; + h.x8 = h8; + h.x9 = h9; + } + } +} \ No newline at end of file diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_tobytes.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_tobytes.cs new file mode 100644 index 000000000..601f88f28 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/fe_tobytes.cs @@ -0,0 +1,145 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + Preconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + + Write p=2^255-19; q=floor(h/p). + Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). + + Proof: + Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. + Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4. + + Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). + Then 0> 0); + s[offset + 1] = (byte) (h0 >> 8); + s[offset + 2] = (byte) (h0 >> 16); + s[offset + 3] = (byte) ((h0 >> 24) | (h1 << 2)); + s[offset + 4] = (byte) (h1 >> 6); + s[offset + 5] = (byte) (h1 >> 14); + s[offset + 6] = (byte) ((h1 >> 22) | (h2 << 3)); + s[offset + 7] = (byte) (h2 >> 5); + s[offset + 8] = (byte) (h2 >> 13); + s[offset + 9] = (byte) ((h2 >> 21) | (h3 << 5)); + s[offset + 10] = (byte) (h3 >> 3); + s[offset + 11] = (byte) (h3 >> 11); + s[offset + 12] = (byte) ((h3 >> 19) | (h4 << 6)); + s[offset + 13] = (byte) (h4 >> 2); + s[offset + 14] = (byte) (h4 >> 10); + s[offset + 15] = (byte) (h4 >> 18); + s[offset + 16] = (byte) (h5 >> 0); + s[offset + 17] = (byte) (h5 >> 8); + s[offset + 18] = (byte) (h5 >> 16); + s[offset + 19] = (byte) ((h5 >> 24) | (h6 << 1)); + s[offset + 20] = (byte) (h6 >> 7); + s[offset + 21] = (byte) (h6 >> 15); + s[offset + 22] = (byte) ((h6 >> 23) | (h7 << 3)); + s[offset + 23] = (byte) (h7 >> 5); + s[offset + 24] = (byte) (h7 >> 13); + s[offset + 25] = (byte) ((h7 >> 21) | (h8 << 4)); + s[offset + 26] = (byte) (h8 >> 4); + s[offset + 27] = (byte) (h8 >> 12); + s[offset + 28] = (byte) ((h8 >> 20) | (h9 << 6)); + s[offset + 29] = (byte) (h9 >> 2); + s[offset + 30] = (byte) (h9 >> 10); + s[offset + 31] = (byte) (h9 >> 18); + } + } + + internal static void fe_reduce(out FieldElement hr, ref FieldElement h) + { + int h0 = h.x0; + int h1 = h.x1; + int h2 = h.x2; + int h3 = h.x3; + int h4 = h.x4; + int h5 = h.x5; + int h6 = h.x6; + int h7 = h.x7; + int h8 = h.x8; + int h9 = h.x9; + + int q; + + q = (19 * h9 + (1 << 24)) >> 25; + q = (h0 + q) >> 26; + q = (h1 + q) >> 25; + q = (h2 + q) >> 26; + q = (h3 + q) >> 25; + q = (h4 + q) >> 26; + q = (h5 + q) >> 25; + q = (h6 + q) >> 26; + q = (h7 + q) >> 25; + q = (h8 + q) >> 26; + q = (h9 + q) >> 25; + + /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */ + h0 += 19 * q; + /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ + + var carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26; + var carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25; + var carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26; + var carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25; + var carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26; + var carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25; + var carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26; + var carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25; + var carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26; + var carry9 = h9 >> 25; h9 -= carry9 << 25; + /* h10 = carry9 */ + + hr.x0 = h0; + hr.x1 = h1; + hr.x2 = h2; + hr.x3 = h3; + hr.x4 = h4; + hr.x5 = h5; + hr.x6 = h6; + hr.x7 = h7; + hr.x8 = h8; + hr.x9 = h9; + } + } +} \ No newline at end of file diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_add.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_add.cs new file mode 100644 index 000000000..de8e08f12 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_add.cs @@ -0,0 +1,73 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class GroupOperations + { + /* + r = p + q + */ + + internal static void ge_add(out GroupElementP1P1 r, ref GroupElementP3 p, ref GroupElementCached q) + { + FieldElement t0; + + /* qhasm: YpX1 = Y1+X1 */ + /* asm 1: fe_add(>YpX1=fe#1,YpX1=r.X,YmX1=fe#2,YmX1=r.Y,A=fe#3,A=r.Z,B=fe#2,B=r.Y,C=fe#4,C=r.T,ZZ=fe#1,ZZ=r.X,D=fe#5,D=t0,X3=fe#1,X3=r.X,Y3=fe#2,Y3=r.Y,Z3=fe#3,Z3=r.Z,T3=fe#4,T3=r.T,> 3] >> (i & 7))); + + for (int i = 0; i < 256; ++i) + { + if (r[i] != 0) + { + for (int b = 1; b <= 6 && (i + b) < 256; ++b) + { + if (r[i + b] != 0) + { + if (r[i] + (r[i + b] << b) <= 15) + { + r[i] += (sbyte)(r[i + b] << b); r[i + b] = 0; + } + else if (r[i] - (r[i + b] << b) >= -15) + { + r[i] -= (sbyte)(r[i + b] << b); + for (int k = i + b; k < 256; ++k) + { + if (r[k] == 0) + { + r[k] = 1; + break; + } + r[k] = 0; + } + } + else + break; + } + } + } + } + } + + /* + r = a * A + b * B + where a = a[0]+256*a[1]+...+256^31 a[31]. + and b = b[0]+256*b[1]+...+256^31 b[31]. + B is the Ed25519 base point (x,4/5) with x positive. + */ + + public static void ge_double_scalarmult_vartime(out GroupElementP2 r, byte[] a, ref GroupElementP3 A, byte[] b) + { + GroupElementPreComp[] Bi = LookupTables.Base2; + // todo: Perhaps remove these allocations? + sbyte[] aslide = new sbyte[256]; + sbyte[] bslide = new sbyte[256]; + GroupElementCached[] Ai = new GroupElementCached[8]; /* A,3A,5A,7A,9A,11A,13A,15A */ + GroupElementP1P1 t; + GroupElementP3 u; + GroupElementP3 A2; + int i; + + slide(aslide, a); + slide(bslide, b); + + ge_p3_to_cached(out Ai[0], ref A); + ge_p3_dbl(out t, ref A); ge_p1p1_to_p3(out A2, ref t); + ge_add(out t, ref A2, ref Ai[0]); ge_p1p1_to_p3(out u, ref t); ge_p3_to_cached(out Ai[1], ref u); + ge_add(out t, ref A2, ref Ai[1]); ge_p1p1_to_p3(out u, ref t); ge_p3_to_cached(out Ai[2], ref u); + ge_add(out t, ref A2, ref Ai[2]); ge_p1p1_to_p3(out u, ref t); ge_p3_to_cached(out Ai[3], ref u); + ge_add(out t, ref A2, ref Ai[3]); ge_p1p1_to_p3(out u, ref t); ge_p3_to_cached(out Ai[4], ref u); + ge_add(out t, ref A2, ref Ai[4]); ge_p1p1_to_p3(out u, ref t); ge_p3_to_cached(out Ai[5], ref u); + ge_add(out t, ref A2, ref Ai[5]); ge_p1p1_to_p3(out u, ref t); ge_p3_to_cached(out Ai[6], ref u); + ge_add(out t, ref A2, ref Ai[6]); ge_p1p1_to_p3(out u, ref t); ge_p3_to_cached(out Ai[7], ref u); + + ge_p2_0(out r); + + for (i = 255; i >= 0; --i) + { + if ((aslide[i] != 0) || (bslide[i] != 0)) break; + } + + for (; i >= 0; --i) + { + ge_p2_dbl(out t, ref r); + + if (aslide[i] > 0) + { + ge_p1p1_to_p3(out u, ref t); + ge_add(out t, ref u, ref Ai[aslide[i] / 2]); + } + else if (aslide[i] < 0) + { + ge_p1p1_to_p3(out u, ref t); + ge_sub(out t, ref u, ref Ai[(-aslide[i]) / 2]); + } + + if (bslide[i] > 0) + { + ge_p1p1_to_p3(out u, ref t); + ge_madd(out t, ref u, ref Bi[bslide[i] / 2]); + } + else if (bslide[i] < 0) + { + ge_p1p1_to_p3(out u, ref t); + ge_msub(out t, ref u, ref Bi[(-bslide[i]) / 2]); + } + + ge_p1p1_to_p2(out r, ref t); + } + } + + } +} \ No newline at end of file diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_frombytes.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_frombytes.cs new file mode 100644 index 000000000..2e7abe9d4 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_frombytes.cs @@ -0,0 +1,50 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class GroupOperations + { + public static int ge_frombytes_negate_vartime(out GroupElementP3 h, byte[] data, int offset) + { + FieldElement u, v, v3, vxx, check; + + FieldOperations.fe_frombytes(out h.Y, data, offset); + FieldOperations.fe_1(out h.Z); + FieldOperations.fe_sq(out u, ref h.Y); + FieldOperations.fe_mul(out v, ref u, ref LookupTables.d); + FieldOperations.fe_sub(out u, ref u, ref h.Z); /* u = y^2-1 */ + FieldOperations.fe_add(out v, ref v, ref h.Z); /* v = dy^2+1 */ + + FieldOperations.fe_sq(out v3, ref v); + FieldOperations.fe_mul(out v3, ref v3, ref v); /* v3 = v^3 */ + FieldOperations.fe_sq(out h.X, ref v3); + FieldOperations.fe_mul(out h.X, ref h.X, ref v); + FieldOperations.fe_mul(out h.X, ref h.X, ref u); /* x = uv^7 */ + + FieldOperations.fe_pow22523(out h.X, ref h.X); /* x = (uv^7)^((q-5)/8) */ + FieldOperations.fe_mul(out h.X, ref h.X, ref v3); + FieldOperations.fe_mul(out h.X, ref h.X, ref u); /* x = uv^3(uv^7)^((q-5)/8) */ + + FieldOperations.fe_sq(out vxx, ref h.X); + FieldOperations.fe_mul(out vxx, ref vxx, ref v); + FieldOperations.fe_sub(out check, ref vxx, ref u); /* vx^2-u */ + if (FieldOperations.fe_isnonzero(ref check) != 0) + { + FieldOperations.fe_add(out check, ref vxx, ref u); /* vx^2+u */ + if (FieldOperations.fe_isnonzero(ref check) != 0) + { + h = default(GroupElementP3); + return -1; + } + FieldOperations.fe_mul(out h.X, ref h.X, ref LookupTables.sqrtm1); + } + + if (FieldOperations.fe_isnegative(ref h.X) == (data[offset + 31] >> 7)) + FieldOperations.fe_neg(out h.X, ref h.X); + + FieldOperations.fe_mul(out h.T, ref h.X, ref h.Y); + return 0; + } + + } +} \ No newline at end of file diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_madd.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_madd.cs new file mode 100644 index 000000000..547e17d86 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_madd.cs @@ -0,0 +1,69 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class GroupOperations + { + /* + r = p + q + */ + public static void ge_madd(out GroupElementP1P1 r, ref GroupElementP3 p, ref GroupElementPreComp q) + { + FieldElement t0; + + /* qhasm: YpX1 = Y1+X1 */ + /* asm 1: fe_add(>YpX1=fe#1,YpX1=r.X,YmX1=fe#2,YmX1=r.Y,A=fe#3,A=r.Z,B=fe#2,B=r.Y,C=fe#4,C=r.T,D=fe#5,D=t0,X3=fe#1,X3=r.X,Y3=fe#2,Y3=r.Y,Z3=fe#3,Z3=r.Z,T3=fe#4,T3=r.T,YpX1=fe#1,YpX1=r.X,YmX1=fe#2,YmX1=r.Y,A=fe#3,A=r.Z,B=fe#2,B=r.Y,C=fe#4,C=r.T,D=fe#5,D=t0,X3=fe#1,X3=r.X,Y3=fe#2,Y3=r.Y,Z3=fe#3,Z3=r.Z,T3=fe#4,T3=r.T,XX=fe#1,XX=r.X,YY=fe#3,YY=r.Z,B=fe#4,B=r.T,A=fe#2,A=r.Y,AA=fe#5,AA=t0,Y3=fe#2,Y3=r.Y,Z3=fe#3,Z3=r.Z,X3=fe#1,X3=r.X,T3=fe#4,T3=r.T,>= 31; /* 1: yes; 0: no */ + return (byte)y; + } + + static byte negative(sbyte b) + { + var x = unchecked((ulong)b); /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ + x >>= 63; /* 1: yes; 0: no */ + return (byte)x; + } + + static void cmov(ref GroupElementPreComp t, ref GroupElementPreComp u, byte b) + { + FieldOperations.fe_cmov(ref t.yplusx, ref u.yplusx, b); + FieldOperations.fe_cmov(ref t.yminusx, ref u.yminusx, b); + FieldOperations.fe_cmov(ref t.xy2d, ref u.xy2d, b); + } + + static void select(out GroupElementPreComp t, int pos, sbyte b) + { + GroupElementPreComp minust; + var bnegative = negative(b); + var babs = (byte)(b - (((-bnegative) & b) << 1)); + + ge_precomp_0(out t); + var table = LookupTables.Base[pos]; + cmov(ref t, ref table[0], equal(babs, 1)); + cmov(ref t, ref table[1], equal(babs, 2)); + cmov(ref t, ref table[2], equal(babs, 3)); + cmov(ref t, ref table[3], equal(babs, 4)); + cmov(ref t, ref table[4], equal(babs, 5)); + cmov(ref t, ref table[5], equal(babs, 6)); + cmov(ref t, ref table[6], equal(babs, 7)); + cmov(ref t, ref table[7], equal(babs, 8)); + minust.yplusx = t.yminusx; + minust.yminusx = t.yplusx; + FieldOperations.fe_neg(out minust.xy2d, ref t.xy2d); + cmov(ref t, ref minust, bnegative); + } + + /* + h = a * B + where a = a[0]+256*a[1]+...+256^31 a[31] + B is the Ed25519 base point (x,4/5) with x positive. + + Preconditions: + a[31] <= 127 + */ + + public static void ge_scalarmult_base(out GroupElementP3 h, byte[] a, int offset) + { + // todo: Perhaps remove this allocation + var e = new sbyte[64]; + sbyte carry; + + GroupElementP1P1 r; + GroupElementP2 s; + GroupElementPreComp t; + + for (int i = 0; i < 32; ++i) + { + e[2 * i + 0] = (sbyte)((a[offset + i] >> 0) & 15); + e[2 * i + 1] = (sbyte)((a[offset + i] >> 4) & 15); + } + /* each e[i] is between 0 and 15 */ + /* e[63] is between 0 and 7 */ + + carry = 0; + for (int i = 0; i < 63; ++i) + { + e[i] += carry; + carry = (sbyte)(e[i] + 8); + carry >>= 4; + e[i] -= (sbyte)(carry << 4); + } + e[63] += carry; + /* each e[i] is between -8 and 8 */ + + ge_p3_0(out h); + for (int i = 1; i < 64; i += 2) + { + select(out t, i / 2, e[i]); + ge_madd(out r, ref h, ref t); ge_p1p1_to_p3(out h, ref r); + } + + ge_p3_dbl(out r, ref h); ge_p1p1_to_p2(out s, ref r); + ge_p2_dbl(out r, ref s); ge_p1p1_to_p2(out s, ref r); + ge_p2_dbl(out r, ref s); ge_p1p1_to_p2(out s, ref r); + ge_p2_dbl(out r, ref s); ge_p1p1_to_p3(out h, ref r); + + for (int i = 0; i < 64; i += 2) + { + select(out t, i / 2, e[i]); + ge_madd(out r, ref h, ref t); ge_p1p1_to_p3(out h, ref r); + } + } + + } +} \ No newline at end of file diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_sub.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_sub.cs new file mode 100644 index 000000000..c0b9ba5a2 --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/ge_sub.cs @@ -0,0 +1,74 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class GroupOperations + { + /* + r = p - q + */ + + public static void ge_sub(out GroupElementP1P1 r, ref GroupElementP3 p, ref GroupElementCached q) + { + FieldElement t0; + + /* qhasm: YpX1 = Y1+X1 */ + /* asm 1: fe_add(>YpX1=fe#1,YpX1=r.X,YmX1=fe#2,YmX1=r.Y,A=fe#3,A=r.Z,B=fe#2,B=r.Y,C=fe#4,C=r.T,ZZ=fe#1,ZZ=r.X,D=fe#5,D=t0,X3=fe#1,X3=r.X,Y3=fe#2,Y3=r.Y,Z3=fe#3,Z3=r.Z,T3=fe#4,T3=r.T,> 5); + long a2 = 2097151 & (load_3(a, 5) >> 2); + long a3 = 2097151 & (load_4(a, 7) >> 7); + long a4 = 2097151 & (load_4(a, 10) >> 4); + long a5 = 2097151 & (load_3(a, 13) >> 1); + long a6 = 2097151 & (load_4(a, 15) >> 6); + long a7 = 2097151 & (load_3(a, 18) >> 3); + long a8 = 2097151 & load_3(a, 21); + long a9 = 2097151 & (load_4(a, 23) >> 5); + long a10 = 2097151 & (load_3(a, 26) >> 2); + long a11 = (load_4(a, 28) >> 7); + long b0 = 2097151 & load_3(b, 0); + long b1 = 2097151 & (load_4(b, 2) >> 5); + long b2 = 2097151 & (load_3(b, 5) >> 2); + long b3 = 2097151 & (load_4(b, 7) >> 7); + long b4 = 2097151 & (load_4(b, 10) >> 4); + long b5 = 2097151 & (load_3(b, 13) >> 1); + long b6 = 2097151 & (load_4(b, 15) >> 6); + long b7 = 2097151 & (load_3(b, 18) >> 3); + long b8 = 2097151 & load_3(b, 21); + long b9 = 2097151 & (load_4(b, 23) >> 5); + long b10 = 2097151 & (load_3(b, 26) >> 2); + long b11 = (load_4(b, 28) >> 7); + long c0 = 2097151 & load_3(c, 0); + long c1 = 2097151 & (load_4(c, 2) >> 5); + long c2 = 2097151 & (load_3(c, 5) >> 2); + long c3 = 2097151 & (load_4(c, 7) >> 7); + long c4 = 2097151 & (load_4(c, 10) >> 4); + long c5 = 2097151 & (load_3(c, 13) >> 1); + long c6 = 2097151 & (load_4(c, 15) >> 6); + long c7 = 2097151 & (load_3(c, 18) >> 3); + long c8 = 2097151 & load_3(c, 21); + long c9 = 2097151 & (load_4(c, 23) >> 5); + long c10 = 2097151 & (load_3(c, 26) >> 2); + long c11 = (load_4(c, 28) >> 7); + long s0; + long s1; + long s2; + long s3; + long s4; + long s5; + long s6; + long s7; + long s8; + long s9; + long s10; + long s11; + long s12; + long s13; + long s14; + long s15; + long s16; + long s17; + long s18; + long s19; + long s20; + long s21; + long s22; + long s23; + long carry0; + long carry1; + long carry2; + long carry3; + long carry4; + long carry5; + long carry6; + long carry7; + long carry8; + long carry9; + long carry10; + long carry11; + long carry12; + long carry13; + long carry14; + long carry15; + long carry16; + long carry17; + long carry18; + long carry19; + long carry20; + long carry21; + long carry22; + + s0 = c0 + a0 * b0; + s1 = c1 + a0 * b1 + a1 * b0; + s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0; + s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; + s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0; + s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0; + s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0; + s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0; + s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1 + a8 * b0; + s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0; + s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0; + s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0; + s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1; + s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2; + s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + a9 * b5 + a10 * b4 + a11 * b3; + s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + a10 * b5 + a11 * b4; + s16 = a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5; + s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6; + s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7; + s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8; + s20 = a9 * b11 + a10 * b10 + a11 * b9; + s21 = a10 * b11 + a11 * b10; + s22 = a11 * b11; + s23 = 0; + + carry0 = (s0 + (1 << 20)) >> 21; s1 += carry0; s0 -= carry0 << 21; + carry2 = (s2 + (1 << 20)) >> 21; s3 += carry2; s2 -= carry2 << 21; + carry4 = (s4 + (1 << 20)) >> 21; s5 += carry4; s4 -= carry4 << 21; + carry6 = (s6 + (1 << 20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + carry12 = (s12 + (1 << 20)) >> 21; s13 += carry12; s12 -= carry12 << 21; + carry14 = (s14 + (1 << 20)) >> 21; s15 += carry14; s14 -= carry14 << 21; + carry16 = (s16 + (1 << 20)) >> 21; s17 += carry16; s16 -= carry16 << 21; + carry18 = (s18 + (1 << 20)) >> 21; s19 += carry18; s18 -= carry18 << 21; + carry20 = (s20 + (1 << 20)) >> 21; s21 += carry20; s20 -= carry20 << 21; + carry22 = (s22 + (1 << 20)) >> 21; s23 += carry22; s22 -= carry22 << 21; + + carry1 = (s1 + (1 << 20)) >> 21; s2 += carry1; s1 -= carry1 << 21; + carry3 = (s3 + (1 << 20)) >> 21; s4 += carry3; s3 -= carry3 << 21; + carry5 = (s5 + (1 << 20)) >> 21; s6 += carry5; s5 -= carry5 << 21; + carry7 = (s7 + (1 << 20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + carry13 = (s13 + (1 << 20)) >> 21; s14 += carry13; s13 -= carry13 << 21; + carry15 = (s15 + (1 << 20)) >> 21; s16 += carry15; s15 -= carry15 << 21; + carry17 = (s17 + (1 << 20)) >> 21; s18 += carry17; s17 -= carry17 << 21; + carry19 = (s19 + (1 << 20)) >> 21; s20 += carry19; s19 -= carry19 << 21; + carry21 = (s21 + (1 << 20)) >> 21; s22 += carry21; s21 -= carry21 << 21; + + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + s23 = 0; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + s22 = 0; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + s21 = 0; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + s20 = 0; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + s19 = 0; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + s18 = 0; + + carry6 = (s6 + (1 << 20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + carry12 = (s12 + (1 << 20)) >> 21; s13 += carry12; s12 -= carry12 << 21; + carry14 = (s14 + (1 << 20)) >> 21; s15 += carry14; s14 -= carry14 << 21; + carry16 = (s16 + (1 << 20)) >> 21; s17 += carry16; s16 -= carry16 << 21; + + carry7 = (s7 + (1 << 20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + carry13 = (s13 + (1 << 20)) >> 21; s14 += carry13; s13 -= carry13 << 21; + carry15 = (s15 + (1 << 20)) >> 21; s16 += carry15; s15 -= carry15 << 21; + + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + s17 = 0; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + s16 = 0; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + s15 = 0; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + s14 = 0; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + s13 = 0; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = (s0 + (1 << 20)) >> 21; s1 += carry0; s0 -= carry0 << 21; + carry2 = (s2 + (1 << 20)) >> 21; s3 += carry2; s2 -= carry2 << 21; + carry4 = (s4 + (1 << 20)) >> 21; s5 += carry4; s4 -= carry4 << 21; + carry6 = (s6 + (1 << 20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + + carry1 = (s1 + (1 << 20)) >> 21; s2 += carry1; s1 -= carry1 << 21; + carry3 = (s3 + (1 << 20)) >> 21; s4 += carry3; s3 -= carry3 << 21; + carry5 = (s5 + (1 << 20)) >> 21; s6 += carry5; s5 -= carry5 << 21; + carry7 = (s7 + (1 << 20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + + unchecked + { + s[0] = (byte)(s0 >> 0); + s[1] = (byte)(s0 >> 8); + s[2] = (byte)((s0 >> 16) | (s1 << 5)); + s[3] = (byte)(s1 >> 3); + s[4] = (byte)(s1 >> 11); + s[5] = (byte)((s1 >> 19) | (s2 << 2)); + s[6] = (byte)(s2 >> 6); + s[7] = (byte)((s2 >> 14) | (s3 << 7)); + s[8] = (byte)(s3 >> 1); + s[9] = (byte)(s3 >> 9); + s[10] = (byte)((s3 >> 17) | (s4 << 4)); + s[11] = (byte)(s4 >> 4); + s[12] = (byte)(s4 >> 12); + s[13] = (byte)((s4 >> 20) | (s5 << 1)); + s[14] = (byte)(s5 >> 7); + s[15] = (byte)((s5 >> 15) | (s6 << 6)); + s[16] = (byte)(s6 >> 2); + s[17] = (byte)(s6 >> 10); + s[18] = (byte)((s6 >> 18) | (s7 << 3)); + s[19] = (byte)(s7 >> 5); + s[20] = (byte)(s7 >> 13); + s[21] = (byte)(s8 >> 0); + s[22] = (byte)(s8 >> 8); + s[23] = (byte)((s8 >> 16) | (s9 << 5)); + s[24] = (byte)(s9 >> 3); + s[25] = (byte)(s9 >> 11); + s[26] = (byte)((s9 >> 19) | (s10 << 2)); + s[27] = (byte)(s10 >> 6); + s[28] = (byte)((s10 >> 14) | (s11 << 7)); + s[29] = (byte)(s11 >> 1); + s[30] = (byte)(s11 >> 9); + s[31] = (byte)(s11 >> 17); + } + } + } +} \ No newline at end of file diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/sc_reduce.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/sc_reduce.cs new file mode 100644 index 000000000..d3554455f --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/sc_reduce.cs @@ -0,0 +1,264 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + internal static partial class ScalarOperations + { + /* + Input: + s[0]+256*s[1]+...+256^63*s[63] = s + + Output: + s[0]+256*s[1]+...+256^31*s[31] = s mod l + where l = 2^252 + 27742317777372353535851937790883648493. + Overwrites s in place. + */ + + public static void sc_reduce(byte[] s) + { + long s0 = 2097151 & load_3(s, 0); + long s1 = 2097151 & (load_4(s, 2) >> 5); + long s2 = 2097151 & (load_3(s, 5) >> 2); + long s3 = 2097151 & (load_4(s, 7) >> 7); + long s4 = 2097151 & (load_4(s, 10) >> 4); + long s5 = 2097151 & (load_3(s, 13) >> 1); + long s6 = 2097151 & (load_4(s, 15) >> 6); + long s7 = 2097151 & (load_3(s, 18) >> 3); + long s8 = 2097151 & load_3(s, 21); + long s9 = 2097151 & (load_4(s, 23) >> 5); + long s10 = 2097151 & (load_3(s, 26) >> 2); + long s11 = 2097151 & (load_4(s, 28) >> 7); + long s12 = 2097151 & (load_4(s, 31) >> 4); + long s13 = 2097151 & (load_3(s, 34) >> 1); + long s14 = 2097151 & (load_4(s, 36) >> 6); + long s15 = 2097151 & (load_3(s, 39) >> 3); + long s16 = 2097151 & load_3(s, 42); + long s17 = 2097151 & (load_4(s, 44) >> 5); + long s18 = 2097151 & (load_3(s, 47) >> 2); + long s19 = 2097151 & (load_4(s, 49) >> 7); + long s20 = 2097151 & (load_4(s, 52) >> 4); + long s21 = 2097151 & (load_3(s, 55) >> 1); + long s22 = 2097151 & (load_4(s, 57) >> 6); + long s23 = (load_4(s, 60) >> 3); + + long carry0; + long carry1; + long carry2; + long carry3; + long carry4; + long carry5; + long carry6; + long carry7; + long carry8; + long carry9; + long carry10; + long carry11; + long carry12; + long carry13; + long carry14; + long carry15; + long carry16; + + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + s23 = 0; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + s22 = 0; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + s21 = 0; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + s20 = 0; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + s19 = 0; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + s18 = 0; + + carry6 = (s6 + (1 << 20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + carry12 = (s12 + (1 << 20)) >> 21; s13 += carry12; s12 -= carry12 << 21; + carry14 = (s14 + (1 << 20)) >> 21; s15 += carry14; s14 -= carry14 << 21; + carry16 = (s16 + (1 << 20)) >> 21; s17 += carry16; s16 -= carry16 << 21; + + carry7 = (s7 + (1 << 20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + carry13 = (s13 + (1 << 20)) >> 21; s14 += carry13; s13 -= carry13 << 21; + carry15 = (s15 + (1 << 20)) >> 21; s16 += carry15; s15 -= carry15 << 21; + + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + s17 = 0; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + s16 = 0; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + s15 = 0; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + s14 = 0; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + s13 = 0; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = (s0 + (1 << 20)) >> 21; s1 += carry0; s0 -= carry0 << 21; + carry2 = (s2 + (1 << 20)) >> 21; s3 += carry2; s2 -= carry2 << 21; + carry4 = (s4 + (1 << 20)) >> 21; s5 += carry4; s4 -= carry4 << 21; + carry6 = (s6 + (1 << 20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + + carry1 = (s1 + (1 << 20)) >> 21; s2 += carry1; s1 -= carry1 << 21; + carry3 = (s3 + (1 << 20)) >> 21; s4 += carry3; s3 -= carry3 << 21; + carry5 = (s5 + (1 << 20)) >> 21; s6 += carry5; s5 -= carry5 << 21; + carry7 = (s7 + (1 << 20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + + unchecked + { + s[0] = (byte)(s0 >> 0); + s[1] = (byte)(s0 >> 8); + s[2] = (byte)((s0 >> 16) | (s1 << 5)); + s[3] = (byte)(s1 >> 3); + s[4] = (byte)(s1 >> 11); + s[5] = (byte)((s1 >> 19) | (s2 << 2)); + s[6] = (byte)(s2 >> 6); + s[7] = (byte)((s2 >> 14) | (s3 << 7)); + s[8] = (byte)(s3 >> 1); + s[9] = (byte)(s3 >> 9); + s[10] = (byte)((s3 >> 17) | (s4 << 4)); + s[11] = (byte)(s4 >> 4); + s[12] = (byte)(s4 >> 12); + s[13] = (byte)((s4 >> 20) | (s5 << 1)); + s[14] = (byte)(s5 >> 7); + s[15] = (byte)((s5 >> 15) | (s6 << 6)); + s[16] = (byte)(s6 >> 2); + s[17] = (byte)(s6 >> 10); + s[18] = (byte)((s6 >> 18) | (s7 << 3)); + s[19] = (byte)(s7 >> 5); + s[20] = (byte)(s7 >> 13); + s[21] = (byte)(s8 >> 0); + s[22] = (byte)(s8 >> 8); + s[23] = (byte)((s8 >> 16) | (s9 << 5)); + s[24] = (byte)(s9 >> 3); + s[25] = (byte)(s9 >> 11); + s[26] = (byte)((s9 >> 19) | (s10 << 2)); + s[27] = (byte)(s10 >> 6); + s[28] = (byte)((s10 >> 14) | (s11 << 7)); + s[29] = (byte)(s11 >> 1); + s[30] = (byte)(s11 >> 9); + s[31] = (byte)(s11 >> 17); + } + } + + } +} \ No newline at end of file diff --git a/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/scalarmult.cs b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/scalarmult.cs new file mode 100644 index 000000000..3a7d8feea --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Ed25519Ref10/scalarmult.cs @@ -0,0 +1,153 @@ +using System; + +namespace Discord.Net.ED25519.Ed25519Ref10 +{ + public static class MontgomeryOperations + { + public static void scalarmult( + byte[] q, int qoffset, + byte[] n, int noffset, + byte[] p, int poffset) + { + FieldElement p0, q0; + FieldOperations.fe_frombytes2(out p0, p, poffset); + scalarmult(out q0, n, noffset, ref p0); + FieldOperations.fe_tobytes(q, qoffset, ref q0); + } + + internal static void scalarmult( + out FieldElement q, + byte[] n, int noffset, + ref FieldElement p) + { + byte[] e = new byte[32];//ToDo: remove allocation + FieldElement x1, x2, x3; + FieldElement z2, z3; + FieldElement tmp0, tmp1; + + for (int i = 0; i < 32; ++i) + e[i] = n[noffset + i]; + ScalarOperations.sc_clamp(e, 0); + x1 = p; + FieldOperations.fe_1(out x2); + FieldOperations.fe_0(out z2); + x3 = x1; + FieldOperations.fe_1(out z3); + + uint swap = 0; + for (int pos = 254; pos >= 0; --pos) + { + uint b = (uint)(e[pos / 8] >> (pos & 7)); + b &= 1; + swap ^= b; + FieldOperations.fe_cswap(ref x2, ref x3, swap); + FieldOperations.fe_cswap(ref z2, ref z3, swap); + swap = b; + + /* qhasm: enter ladder */ + + /* qhasm: D = X3-Z3 */ + /* asm 1: fe_sub(>D=fe#5,D=tmp0,B=fe#6,B=tmp1,A=fe#1,A=x2,C=fe#2,C=z2,DA=fe#4,DA=z3,CB=fe#2,CB=z2,BB=fe#5,BB=tmp0,AA=fe#6,AA=tmp1,t0=fe#3,t0=x3,t1=fe#2,t1=z2,X4=fe#1,X4=x2,E=fe#6,E=tmp1,t2=fe#2,t2=z2,t3=fe#4,t3=z3,X5=fe#3,X5=x3,t4=fe#5,t4=tmp0,Z5=fe#4,x1,Z5=z3,x1,Z4=fe#2,Z4=z2, _state; + private readonly byte[] _buffer; + private ulong _totalBytes; + public const int BlockSize = 128; + private static readonly byte[] _padding = new byte[] { 0x80 }; + + /// + /// Allocation and initialization of the new SHA-512 object. + /// + public Sha512() + { + _buffer = new byte[BlockSize];//todo: remove allocation + Init(); + } + + /// + /// Performs an initialization of internal SHA-512 state. + /// + public void Init() + { + Sha512Internal.Sha512Init(out _state); + _totalBytes = 0; + } + + /// + /// Updates internal state with data from the provided array segment. + /// + /// Array segment + public void Update(ArraySegment data) + { + Update(data.Array, data.Offset, data.Count); + } + + /// + /// Updates internal state with data from the provided array. + /// + /// Array of bytes + /// Offset of byte sequence + /// Sequence length + public void Update(byte[] data, int index, int length) + { + + Array16 block; + int bytesInBuffer = (int)_totalBytes & (BlockSize - 1); + _totalBytes += (uint)length; + + if (_totalBytes >= ulong.MaxValue / 8) + throw new InvalidOperationException("Too much data"); + // Fill existing buffer + if (bytesInBuffer != 0) + { + var toCopy = Math.Min(BlockSize - bytesInBuffer, length); + Buffer.BlockCopy(data, index, _buffer, bytesInBuffer, toCopy); + index += toCopy; + length -= toCopy; + bytesInBuffer += toCopy; + if (bytesInBuffer == BlockSize) + { + ByteIntegerConverter.Array16LoadBigEndian64(out block, _buffer, 0); + Sha512Internal.Core(out _state, ref _state, ref block); + CryptoBytes.InternalWipe(_buffer, 0, _buffer.Length); + bytesInBuffer = 0; + } + } + // Hash complete blocks without copying + while (length >= BlockSize) + { + ByteIntegerConverter.Array16LoadBigEndian64(out block, data, index); + Sha512Internal.Core(out _state, ref _state, ref block); + index += BlockSize; + length -= BlockSize; + } + // Copy remainder into buffer + if (length > 0) + { + Buffer.BlockCopy(data, index, _buffer, bytesInBuffer, length); + } + } + + /// + /// Finalizes SHA-512 hashing + /// + /// Output buffer + public void Finalize(ArraySegment output) + { + Preconditions.NotNull(output.Array, nameof(output)); + if (output.Count != 64) + throw new ArgumentException("Output should be 64 in length"); + + Update(_padding, 0, _padding.Length); + Array16 block; + ByteIntegerConverter.Array16LoadBigEndian64(out block, _buffer, 0); + CryptoBytes.InternalWipe(_buffer, 0, _buffer.Length); + int bytesInBuffer = (int)_totalBytes & (BlockSize - 1); + if (bytesInBuffer > BlockSize - 16) + { + Sha512Internal.Core(out _state, ref _state, ref block); + block = default(Array16); + } + block.x15 = (_totalBytes - 1) * 8; + Sha512Internal.Core(out _state, ref _state, ref block); + + ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 0, _state.x0); + ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 8, _state.x1); + ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 16, _state.x2); + ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 24, _state.x3); + ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 32, _state.x4); + ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 40, _state.x5); + ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 48, _state.x6); + ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 56, _state.x7); + _state = default(Array8); + } + + /// + /// Finalizes SHA-512 hashing. + /// + /// Hash bytes + public byte[] Finalize() + { + var result = new byte[64]; + Finalize(new ArraySegment(result)); + return result; + } + + /// + /// Calculates SHA-512 hash value for the given bytes array. + /// + /// Data bytes array + /// Hash bytes + public static byte[] Hash(byte[] data) + { + return Hash(data, 0, data.Length); + } + + /// + /// Calculates SHA-512 hash value for the given bytes array. + /// + /// Data bytes array + /// Offset of byte sequence + /// Sequence length + /// Hash bytes + public static byte[] Hash(byte[] data, int index, int length) + { + var hasher = new Sha512(); + hasher.Update(data, index, length); + return hasher.Finalize(); + } + } +} diff --git a/src/Discord.Net.Rest/Net/ED25519/Sha512Internal.cs b/src/Discord.Net.Rest/Net/ED25519/Sha512Internal.cs new file mode 100644 index 000000000..df8842d8d --- /dev/null +++ b/src/Discord.Net.Rest/Net/ED25519/Sha512Internal.cs @@ -0,0 +1,447 @@ +using System; +using System.Collections.Generic; + +namespace Discord.Net.ED25519 +{ + internal static class Sha512Internal + { + private static readonly ulong[] K = new ulong[] + { + 0x428a2f98d728ae22,0x7137449123ef65cd,0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc, + 0x3956c25bf348b538,0x59f111f1b605d019,0x923f82a4af194f9b,0xab1c5ed5da6d8118, + 0xd807aa98a3030242,0x12835b0145706fbe,0x243185be4ee4b28c,0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f,0x80deb1fe3b1696b1,0x9bdc06a725c71235,0xc19bf174cf692694, + 0xe49b69c19ef14ad2,0xefbe4786384f25e3,0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65, + 0x2de92c6f592b0275,0x4a7484aa6ea6e483,0x5cb0a9dcbd41fbd4,0x76f988da831153b5, + 0x983e5152ee66dfab,0xa831c66d2db43210,0xb00327c898fb213f,0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2,0xd5a79147930aa725,0x06ca6351e003826f,0x142929670a0e6e70, + 0x27b70a8546d22ffc,0x2e1b21385c26c926,0x4d2c6dfc5ac42aed,0x53380d139d95b3df, + 0x650a73548baf63de,0x766a0abb3c77b2a8,0x81c2c92e47edaee6,0x92722c851482353b, + 0xa2bfe8a14cf10364,0xa81a664bbc423001,0xc24b8b70d0f89791,0xc76c51a30654be30, + 0xd192e819d6ef5218,0xd69906245565a910,0xf40e35855771202a,0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8,0x1e376c085141ab53,0x2748774cdf8eeb99,0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb,0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc,0x78a5636f43172f60,0x84c87814a1f0ab72,0x8cc702081a6439ec, + 0x90befffa23631e28,0xa4506cebde82bde9,0xbef9a3f7b2c67915,0xc67178f2e372532b, + 0xca273eceea26619c,0xd186b8c721c0c207,0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178, + 0x06f067aa72176fba,0x0a637dc5a2c898a6,0x113f9804bef90dae,0x1b710b35131c471b, + 0x28db77f523047d84,0x32caab7b40c72493,0x3c9ebe0a15c9bebc,0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6,0x597f299cfc657e2a,0x5fcb6fab3ad6faec,0x6c44198c4a475817 + }; + + internal static void Sha512Init(out Array8 state) + { + state.x0 = 0x6a09e667f3bcc908; + state.x1 = 0xbb67ae8584caa73b; + state.x2 = 0x3c6ef372fe94f82b; + state.x3 = 0xa54ff53a5f1d36f1; + state.x4 = 0x510e527fade682d1; + state.x5 = 0x9b05688c2b3e6c1f; + state.x6 = 0x1f83d9abfb41bd6b; + state.x7 = 0x5be0cd19137e2179; + } + + internal static void Core(out Array8 outputState, ref Array8 inputState, ref Array16 input) + { + unchecked + { + var a = inputState.x0; + var b = inputState.x1; + var c = inputState.x2; + var d = inputState.x3; + var e = inputState.x4; + var f = inputState.x5; + var g = inputState.x6; + var h = inputState.x7; + + var w0 = input.x0; + var w1 = input.x1; + var w2 = input.x2; + var w3 = input.x3; + var w4 = input.x4; + var w5 = input.x5; + var w6 = input.x6; + var w7 = input.x7; + var w8 = input.x8; + var w9 = input.x9; + var w10 = input.x10; + var w11 = input.x11; + var w12 = input.x12; + var w13 = input.x13; + var w14 = input.x14; + var w15 = input.x15; + + int t = 0; + while (true) + { + ulong t1, t2; + + {//0 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w0; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//1 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w1; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//2 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w2; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//3 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w3; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//4 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w4; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//5 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w5; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//6 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w6; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//7 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w7; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//8 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w8; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//9 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w9; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//10 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w10; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//11 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w11; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//12 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w12; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//13 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w13; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//14 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w14; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//15 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w15; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + if (t == 80) + break; + + w0 += ((w14 >> 19) ^ (w14 << (64 - 19)) ^ (w14 >> 61) ^ (w14 << (64 - 61)) ^ (w14 >> 6)) + + w9 + + ((w1 >> 1) ^ (w1 << (64 - 1)) ^ (w1 >> 8) ^ (w1 << (64 - 8)) ^ (w1 >> 7)); + w1 += ((w15 >> 19) ^ (w15 << (64 - 19)) ^ (w15 >> 61) ^ (w15 << (64 - 61)) ^ (w15 >> 6)) + + w10 + + ((w2 >> 1) ^ (w2 << (64 - 1)) ^ (w2 >> 8) ^ (w2 << (64 - 8)) ^ (w2 >> 7)); + w2 += ((w0 >> 19) ^ (w0 << (64 - 19)) ^ (w0 >> 61) ^ (w0 << (64 - 61)) ^ (w0 >> 6)) + + w11 + + ((w3 >> 1) ^ (w3 << (64 - 1)) ^ (w3 >> 8) ^ (w3 << (64 - 8)) ^ (w3 >> 7)); + w3 += ((w1 >> 19) ^ (w1 << (64 - 19)) ^ (w1 >> 61) ^ (w1 << (64 - 61)) ^ (w1 >> 6)) + + w12 + + ((w4 >> 1) ^ (w4 << (64 - 1)) ^ (w4 >> 8) ^ (w4 << (64 - 8)) ^ (w4 >> 7)); + w4 += ((w2 >> 19) ^ (w2 << (64 - 19)) ^ (w2 >> 61) ^ (w2 << (64 - 61)) ^ (w2 >> 6)) + + w13 + + ((w5 >> 1) ^ (w5 << (64 - 1)) ^ (w5 >> 8) ^ (w5 << (64 - 8)) ^ (w5 >> 7)); + w5 += ((w3 >> 19) ^ (w3 << (64 - 19)) ^ (w3 >> 61) ^ (w3 << (64 - 61)) ^ (w3 >> 6)) + + w14 + + ((w6 >> 1) ^ (w6 << (64 - 1)) ^ (w6 >> 8) ^ (w6 << (64 - 8)) ^ (w6 >> 7)); + w6 += ((w4 >> 19) ^ (w4 << (64 - 19)) ^ (w4 >> 61) ^ (w4 << (64 - 61)) ^ (w4 >> 6)) + + w15 + + ((w7 >> 1) ^ (w7 << (64 - 1)) ^ (w7 >> 8) ^ (w7 << (64 - 8)) ^ (w7 >> 7)); + w7 += ((w5 >> 19) ^ (w5 << (64 - 19)) ^ (w5 >> 61) ^ (w5 << (64 - 61)) ^ (w5 >> 6)) + + w0 + + ((w8 >> 1) ^ (w8 << (64 - 1)) ^ (w8 >> 8) ^ (w8 << (64 - 8)) ^ (w8 >> 7)); + w8 += ((w6 >> 19) ^ (w6 << (64 - 19)) ^ (w6 >> 61) ^ (w6 << (64 - 61)) ^ (w6 >> 6)) + + w1 + + ((w9 >> 1) ^ (w9 << (64 - 1)) ^ (w9 >> 8) ^ (w9 << (64 - 8)) ^ (w9 >> 7)); + w9 += ((w7 >> 19) ^ (w7 << (64 - 19)) ^ (w7 >> 61) ^ (w7 << (64 - 61)) ^ (w7 >> 6)) + + w2 + + ((w10 >> 1) ^ (w10 << (64 - 1)) ^ (w10 >> 8) ^ (w10 << (64 - 8)) ^ (w10 >> 7)); + w10 += ((w8 >> 19) ^ (w8 << (64 - 19)) ^ (w8 >> 61) ^ (w8 << (64 - 61)) ^ (w8 >> 6)) + + w3 + + ((w11 >> 1) ^ (w11 << (64 - 1)) ^ (w11 >> 8) ^ (w11 << (64 - 8)) ^ (w11 >> 7)); + w11 += ((w9 >> 19) ^ (w9 << (64 - 19)) ^ (w9 >> 61) ^ (w9 << (64 - 61)) ^ (w9 >> 6)) + + w4 + + ((w12 >> 1) ^ (w12 << (64 - 1)) ^ (w12 >> 8) ^ (w12 << (64 - 8)) ^ (w12 >> 7)); + w12 += ((w10 >> 19) ^ (w10 << (64 - 19)) ^ (w10 >> 61) ^ (w10 << (64 - 61)) ^ (w10 >> 6)) + + w5 + + ((w13 >> 1) ^ (w13 << (64 - 1)) ^ (w13 >> 8) ^ (w13 << (64 - 8)) ^ (w13 >> 7)); + w13 += ((w11 >> 19) ^ (w11 << (64 - 19)) ^ (w11 >> 61) ^ (w11 << (64 - 61)) ^ (w11 >> 6)) + + w6 + + ((w14 >> 1) ^ (w14 << (64 - 1)) ^ (w14 >> 8) ^ (w14 << (64 - 8)) ^ (w14 >> 7)); + w14 += ((w12 >> 19) ^ (w12 << (64 - 19)) ^ (w12 >> 61) ^ (w12 << (64 - 61)) ^ (w12 >> 6)) + + w7 + + ((w15 >> 1) ^ (w15 << (64 - 1)) ^ (w15 >> 8) ^ (w15 << (64 - 8)) ^ (w15 >> 7)); + w15 += ((w13 >> 19) ^ (w13 << (64 - 19)) ^ (w13 >> 61) ^ (w13 << (64 - 61)) ^ (w13 >> 6)) + + w8 + + ((w0 >> 1) ^ (w0 << (64 - 1)) ^ (w0 >> 8) ^ (w0 << (64 - 8)) ^ (w0 >> 7)); + } + + outputState.x0 = inputState.x0 + a; + outputState.x1 = inputState.x1 + b; + outputState.x2 = inputState.x2 + c; + outputState.x3 = inputState.x3 + d; + outputState.x4 = inputState.x4 + e; + outputState.x5 = inputState.x5 + f; + outputState.x6 = inputState.x6 + g; + outputState.x7 = inputState.x7 + h; + } + } + } +} diff --git a/src/Discord.Net.Rest/Net/Queue/RequestQueueBucket.cs b/src/Discord.Net.Rest/Net/Queue/RequestQueueBucket.cs index 3fb45e55d..d9f4ba57a 100644 --- a/src/Discord.Net.Rest/Net/Queue/RequestQueueBucket.cs +++ b/src/Discord.Net.Rest/Net/Queue/RequestQueueBucket.cs @@ -1,3 +1,4 @@ +using Discord.API; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; @@ -5,6 +6,7 @@ using System.Diagnostics; #endif using System.IO; +using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; @@ -65,7 +67,9 @@ public async Task SendAsync(RestRequest request) try { var response = await request.SendAsync().ConfigureAwait(false); - info = new RateLimitInfo(response.Headers); + info = new RateLimitInfo(response.Headers, request.Endpoint); + + request.Options.ExecuteRatelimitCallback(info); if (response.StatusCode < (HttpStatusCode)200 || response.StatusCode >= (HttpStatusCode)300) { @@ -97,8 +101,7 @@ public async Task SendAsync(RestRequest request) continue; //Retry default: - int? code = null; - string reason = null; + API.DiscordError error = null; if (response.Stream != null) { try @@ -106,14 +109,14 @@ public async Task SendAsync(RestRequest request) using (var reader = new StreamReader(response.Stream)) using (var jsonReader = new JsonTextReader(reader)) { - var json = JToken.Load(jsonReader); - try { code = json.Value("code"); } catch { }; - try { reason = json.Value("message"); } catch { }; + error = Discord.Rest.DiscordRestClient.Serializer.Deserialize(jsonReader); } } catch { } } - throw new HttpException(response.StatusCode, request, code, reason); + throw new HttpException(response.StatusCode, request, error?.Code, error.Message, error.Errors.IsSpecified + ? error.Errors.Value.Select(x => new DiscordJsonError(x.Name.GetValueOrDefault("root"), x.Errors.Select(y => new DiscordError(y.Code, y.Message)).ToArray())).ToArray() + : null); } } else @@ -351,7 +354,7 @@ private void UpdateRateLimit(int id, IRequest request, RateLimitInfo info, bool if (info.Limit.HasValue && WindowCount != info.Limit.Value) { WindowCount = info.Limit.Value; - _semaphore = info.Remaining.Value; + _semaphore = is429 ? 0 : info.Remaining.Value; #if DEBUG_LIMITS Debug.WriteLine($"[{id}] Upgraded Semaphore to {info.Remaining.Value}/{WindowCount}"); #endif @@ -368,12 +371,12 @@ private void UpdateRateLimit(int id, IRequest request, RateLimitInfo info, bool if (info.RetryAfter.HasValue) { //RetryAfter is more accurate than Reset, where available - resetTick = DateTimeOffset.UtcNow.AddMilliseconds(info.RetryAfter.Value); + resetTick = DateTimeOffset.UtcNow.AddSeconds(info.RetryAfter.Value); #if DEBUG_LIMITS Debug.WriteLine($"[{id}] Retry-After: {info.RetryAfter.Value} ({info.RetryAfter.Value} ms)"); #endif } - else if (info.ResetAfter.HasValue && (request.Options.UseSystemClock.HasValue ? !request.Options.UseSystemClock.Value : false)) + else if (info.ResetAfter.HasValue && (request.Options.UseSystemClock.HasValue && !request.Options.UseSystemClock.Value)) { resetTick = DateTimeOffset.UtcNow.Add(info.ResetAfter.Value); #if DEBUG_LIMITS @@ -431,7 +434,7 @@ private void UpdateRateLimit(int id, IRequest request, RateLimitInfo info, bool if (!hasQueuedReset || resetTick > _resetTick) { _resetTick = resetTick; - LastAttemptAt = resetTick.Value; //Make sure we dont destroy this until after its been reset + LastAttemptAt = resetTick.Value; //Make sure we don't destroy this until after its been reset #if DEBUG_LIMITS Debug.WriteLine($"[{id}] Reset in {(int)Math.Ceiling((resetTick - DateTimeOffset.UtcNow).Value.TotalMilliseconds)} ms"); #endif @@ -452,7 +455,7 @@ private async Task QueueReset(int id, int millis, IRequest request) lock (_lock) { millis = (int)Math.Ceiling((_resetTick.Value - DateTimeOffset.UtcNow).TotalMilliseconds); - if (millis <= 0) //Make sure we havent gotten a more accurate reset time + if (millis <= 0) //Make sure we haven't gotten a more accurate reset time { #if DEBUG_LIMITS Debug.WriteLine($"[{id}] * Reset *"); diff --git a/src/Discord.Net.Rest/Net/RateLimitInfo.cs b/src/Discord.Net.Rest/Net/RateLimitInfo.cs index 6a7df7b01..c08f30c7b 100644 --- a/src/Discord.Net.Rest/Net/RateLimitInfo.cs +++ b/src/Discord.Net.Rest/Net/RateLimitInfo.cs @@ -4,19 +4,42 @@ namespace Discord.Net { - internal struct RateLimitInfo + /// + /// Represents a REST-Based ratelimit info. + /// + public struct RateLimitInfo : IRateLimitInfo { + /// public bool IsGlobal { get; } + + /// public int? Limit { get; } + + /// public int? Remaining { get; } + + /// public int? RetryAfter { get; } + + /// public DateTimeOffset? Reset { get; } + + /// public TimeSpan? ResetAfter { get; } + + /// public string Bucket { get; } + + /// public TimeSpan? Lag { get; } - internal RateLimitInfo(Dictionary headers) + /// + public string Endpoint { get; } + + internal RateLimitInfo(Dictionary headers, string endpoint) { + Endpoint = endpoint; + IsGlobal = headers.TryGetValue("X-RateLimit-Global", out string temp) && bool.TryParse(temp, out var isGlobal) && isGlobal; Limit = headers.TryGetValue("X-RateLimit-Limit", out temp) && @@ -28,7 +51,7 @@ internal RateLimitInfo(Dictionary headers) RetryAfter = headers.TryGetValue("Retry-After", out temp) && int.TryParse(temp, NumberStyles.None, CultureInfo.InvariantCulture, out var retryAfter) ? retryAfter : (int?)null; ResetAfter = headers.TryGetValue("X-RateLimit-Reset-After", out temp) && - double.TryParse(temp, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var resetAfter) ? TimeSpan.FromMilliseconds((long)(resetAfter * 1000)) : (TimeSpan?)null; + double.TryParse(temp, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var resetAfter) ? TimeSpan.FromSeconds(resetAfter) : (TimeSpan?)null; Bucket = headers.TryGetValue("X-RateLimit-Bucket", out temp) ? temp : null; Lag = headers.TryGetValue("Date", out temp) && DateTimeOffset.TryParse(temp, CultureInfo.InvariantCulture, DateTimeStyles.None, out var date) ? DateTimeOffset.UtcNow - date : (TimeSpan?)null; diff --git a/src/Discord.Net.Rest/Utils/HexConverter.cs b/src/Discord.Net.Rest/Utils/HexConverter.cs new file mode 100644 index 000000000..ebd959dcb --- /dev/null +++ b/src/Discord.Net.Rest/Utils/HexConverter.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.Rest +{ + internal class HexConverter + { + public static byte[] HexToByteArray(string hex) + { + if (hex.Length % 2 == 1) + throw new Exception("The binary key cannot have an odd number of digits"); + + byte[] arr = new byte[hex.Length >> 1]; + + for (int i = 0; i < hex.Length >> 1; ++i) + { + arr[i] = (byte)((GetHexVal(hex[i << 1]) << 4) + (GetHexVal(hex[(i << 1) + 1]))); + } + + return arr; + } + private static int GetHexVal(char hex) + { + int val = (int)hex; + //For uppercase A-F letters: + //return val - (val < 58 ? 48 : 55); + //For lowercase a-f letters: + //return val - (val < 58 ? 48 : 87); + //Or the two combined, but a bit slower: + return val - (val < 58 ? 48 : (val < 97 ? 55 : 87)); + } + } +} diff --git a/src/Discord.Net.WebSocket/API/Gateway/ApplicationCommandCreatedUpdatedEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/ApplicationCommandCreatedUpdatedEvent.cs new file mode 100644 index 000000000..91dcbde11 --- /dev/null +++ b/src/Discord.Net.WebSocket/API/Gateway/ApplicationCommandCreatedUpdatedEvent.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Discord.API.Gateway +{ + internal class ApplicationCommandCreatedUpdatedEvent : ApplicationCommand + { + [JsonProperty("guild_id")] + public Optional GuildId { get; set; } + } +} diff --git a/src/Discord.Net.WebSocket/API/Gateway/ExtendedGuild.cs b/src/Discord.Net.WebSocket/API/Gateway/ExtendedGuild.cs index 910f6d909..04ee38c0b 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/ExtendedGuild.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/ExtendedGuild.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; using System; @@ -8,18 +7,29 @@ internal class ExtendedGuild : Guild { [JsonProperty("unavailable")] public bool? Unavailable { get; set; } + [JsonProperty("member_count")] public int MemberCount { get; set; } + [JsonProperty("large")] public bool Large { get; set; } [JsonProperty("presences")] public Presence[] Presences { get; set; } + [JsonProperty("members")] public GuildMember[] Members { get; set; } + [JsonProperty("channels")] public Channel[] Channels { get; set; } + [JsonProperty("joined_at")] public DateTimeOffset JoinedAt { get; set; } + + [JsonProperty("threads")] + public new Channel[] Threads { get; set; } + + [JsonProperty("guild_scheduled_events")] + public GuildScheduledEvent[] GuildScheduledEvents { get; set; } } } diff --git a/src/Discord.Net.WebSocket/API/Gateway/GatewayOpCode.cs b/src/Discord.Net.WebSocket/API/Gateway/GatewayOpCode.cs index 13a2bb462..6f8bf48d4 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/GatewayOpCode.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/GatewayOpCode.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 namespace Discord.API.Gateway { internal enum GatewayOpCode : byte @@ -10,7 +9,7 @@ internal enum GatewayOpCode : byte /// C→S - Used to associate a connection with a token and specify configuration. Identify = 2, /// C→S - Used to update client's status and current game id. - StatusUpdate = 3, + PresenceUpdate = 3, /// C→S - Used to join a particular voice channel. VoiceStateUpdate = 4, /// C→S - Used to ensure the guild's voice server is alive. diff --git a/src/Discord.Net.WebSocket/API/Gateway/GuildBanEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/GuildBanEvent.cs index 59a3304dd..a8a72e791 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/GuildBanEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/GuildBanEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/GuildEmojiUpdateEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/GuildEmojiUpdateEvent.cs index 715341dc5..33c10e648 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/GuildEmojiUpdateEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/GuildEmojiUpdateEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/GuildJoinRequestDeleteEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/GuildJoinRequestDeleteEvent.cs new file mode 100644 index 000000000..cb6fc5f40 --- /dev/null +++ b/src/Discord.Net.WebSocket/API/Gateway/GuildJoinRequestDeleteEvent.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Discord.API.Gateway +{ + internal class GuildJoinRequestDeleteEvent + { + [JsonProperty("user_id")] + public ulong UserId { get; set; } + [JsonProperty("guild_id")] + public ulong GuildId { get; set; } + } +} diff --git a/src/Discord.Net.WebSocket/API/Gateway/GuildMemberAddEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/GuildMemberAddEvent.cs index 350652faf..dd42978fc 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/GuildMemberAddEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/GuildMemberAddEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/GuildMemberRemoveEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/GuildMemberRemoveEvent.cs index 501408a7f..ec7df8fd3 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/GuildMemberRemoveEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/GuildMemberRemoveEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/GuildMemberUpdateEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/GuildMemberUpdateEvent.cs index a234d6da5..0f6fa6f37 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/GuildMemberUpdateEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/GuildMemberUpdateEvent.cs @@ -1,10 +1,13 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; +using System; namespace Discord.API.Gateway { internal class GuildMemberUpdateEvent : GuildMember { + [JsonProperty("joined_at")] + public new DateTimeOffset? JoinedAt { get; set; } + [JsonProperty("guild_id")] public ulong GuildId { get; set; } } diff --git a/src/Discord.Net.WebSocket/API/Gateway/GuildMembersChunkEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/GuildMembersChunkEvent.cs index e401d7fa1..26114bf54 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/GuildMembersChunkEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/GuildMembersChunkEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/GuildRoleCreateEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/GuildRoleCreateEvent.cs index 3409b1c91..3b02164d5 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/GuildRoleCreateEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/GuildRoleCreateEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/GuildRoleDeleteEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/GuildRoleDeleteEvent.cs index dbdaeff67..d9bdb9892 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/GuildRoleDeleteEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/GuildRoleDeleteEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/GuildRoleUpdateEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/GuildRoleUpdateEvent.cs index b04ecb182..bb6a39620 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/GuildRoleUpdateEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/GuildRoleUpdateEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/GuildScheduledEventUserAddRemoveEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/GuildScheduledEventUserAddRemoveEvent.cs new file mode 100644 index 000000000..3fc959125 --- /dev/null +++ b/src/Discord.Net.WebSocket/API/Gateway/GuildScheduledEventUserAddRemoveEvent.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API.Gateway +{ + internal class GuildScheduledEventUserAddRemoveEvent + { + [JsonProperty("guild_scheduled_event_id")] + public ulong EventId { get; set; } + [JsonProperty("guild_id")] + public ulong GuildId { get; set; } + [JsonProperty("user_id")] + public ulong UserId { get; set; } + } +} diff --git a/src/Discord.Net.WebSocket/API/Gateway/GuildStickerUpdateEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/GuildStickerUpdateEvent.cs new file mode 100644 index 000000000..f0ecd3a4f --- /dev/null +++ b/src/Discord.Net.WebSocket/API/Gateway/GuildStickerUpdateEvent.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Discord.API.Gateway +{ + internal class GuildStickerUpdateEvent + { + [JsonProperty("guild_id")] + public ulong GuildId { get; set; } + + [JsonProperty("stickers")] + public Sticker[] Stickers { get; set; } + } +} diff --git a/src/Discord.Net.WebSocket/API/Gateway/GuildSyncEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/GuildSyncEvent.cs index 6b2e6c02f..ba4c1ca60 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/GuildSyncEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/GuildSyncEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/HelloEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/HelloEvent.cs index e1ed9463c..a53a96fd8 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/HelloEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/HelloEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/IdentifyParams.cs b/src/Discord.Net.WebSocket/API/Gateway/IdentifyParams.cs index bb54d4cdd..96c7cb32f 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/IdentifyParams.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/IdentifyParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; using System.Collections.Generic; @@ -16,7 +15,7 @@ internal class IdentifyParams [JsonProperty("shard")] public Optional ShardingParams { get; set; } [JsonProperty("presence")] - public Optional Presence { get; set; } + public Optional Presence { get; set; } [JsonProperty("intents")] public Optional Intents { get; set; } } diff --git a/src/Discord.Net.WebSocket/API/Gateway/InviteCreatedEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/InviteCreatedEvent.cs new file mode 100644 index 000000000..1613cdfa6 --- /dev/null +++ b/src/Discord.Net.WebSocket/API/Gateway/InviteCreatedEvent.cs @@ -0,0 +1,32 @@ +using Discord.API; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API.Gateway +{ + internal class InviteCreatedEvent + { + [JsonProperty("channel_id")] + public ulong ChannelID { get; set; } + [JsonProperty("code")] + public string InviteCode { get; set; } + [JsonProperty("timestamp")] + public Optional RawTimestamp { get; set; } + [JsonProperty("guild_id")] + public ulong? GuildID { get; set; } + [JsonProperty("inviter")] + public Optional Inviter { get; set; } + [JsonProperty("max_age")] + public int RawAge { get; set; } + [JsonProperty("max_uses")] + public int MaxUsers { get; set; } + [JsonProperty("temporary")] + public bool TempInvite { get; set; } + [JsonProperty("uses")] + public int Uses { get; set; } + } +} diff --git a/src/Discord.Net.WebSocket/API/Gateway/InviteDeletedEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/InviteDeletedEvent.cs new file mode 100644 index 000000000..6bdd337f5 --- /dev/null +++ b/src/Discord.Net.WebSocket/API/Gateway/InviteDeletedEvent.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.WebSocket +{ + internal class InviteDeletedEvent + { + [JsonProperty("channel_id")] + public ulong ChannelID { get; set; } + [JsonProperty("guild_id")] + public Optional GuildID { get; set; } + [JsonProperty("code")] + public string Code { get; set; } + } +} diff --git a/src/Discord.Net.WebSocket/API/Gateway/MessageDeleteBulkEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/MessageDeleteBulkEvent.cs index a4cf7d7eb..c503e636d 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/MessageDeleteBulkEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/MessageDeleteBulkEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; using System.Collections.Generic; diff --git a/src/Discord.Net.WebSocket/API/Gateway/ReadyEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/ReadyEvent.cs index ab92d8c36..5cd75dbee 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/ReadyEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/ReadyEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/RecipientEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/RecipientEvent.cs index 336ffd029..778b5708c 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/RecipientEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/RecipientEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/RequestMembersParams.cs b/src/Discord.Net.WebSocket/API/Gateway/RequestMembersParams.cs index 6a8d283ed..f7a63e330 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/RequestMembersParams.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/RequestMembersParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; using System.Collections.Generic; diff --git a/src/Discord.Net.WebSocket/API/Gateway/ResumeParams.cs b/src/Discord.Net.WebSocket/API/Gateway/ResumeParams.cs index ffb46327b..826e8fadd 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/ResumeParams.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/ResumeParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/ResumedEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/ResumedEvent.cs index d1347beae..870ae7366 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/ResumedEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/ResumedEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/StatusUpdateParams.cs b/src/Discord.Net.WebSocket/API/Gateway/StatusUpdateParams.cs index 5fec8b4bd..cbde225d2 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/StatusUpdateParams.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/StatusUpdateParams.cs @@ -1,18 +1,18 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway { [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - internal class StatusUpdateParams + internal class PresenceUpdateParams + { [JsonProperty("status")] public UserStatus Status { get; set; } - [JsonProperty("since"), Int53] + [JsonProperty("since", NullValueHandling = NullValueHandling.Include), Int53] public long? IdleSince { get; set; } [JsonProperty("afk")] public bool IsAFK { get; set; } - [JsonProperty("game")] - public Game Game { get; set; } + [JsonProperty("activities")] + public object[] Activities { get; set; } // TODO, change to interface later } } diff --git a/src/Discord.Net.WebSocket/API/Gateway/ThreadListSyncEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/ThreadListSyncEvent.cs new file mode 100644 index 000000000..5084f6c95 --- /dev/null +++ b/src/Discord.Net.WebSocket/API/Gateway/ThreadListSyncEvent.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +namespace Discord.API.Gateway +{ + internal class ThreadListSyncEvent + { + [JsonProperty("guild_id")] + public ulong GuildId { get; set; } + + [JsonProperty("channel_ids")] + public Optional ChannelIds { get; set; } + + [JsonProperty("threads")] + public Channel[] Threads { get; set; } + + [JsonProperty("members")] + public ThreadMember[] Members { get; set; } + } +} diff --git a/src/Discord.Net.WebSocket/API/Gateway/ThreadMembersUpdate.cs b/src/Discord.Net.WebSocket/API/Gateway/ThreadMembersUpdate.cs new file mode 100644 index 000000000..83d2c0edd --- /dev/null +++ b/src/Discord.Net.WebSocket/API/Gateway/ThreadMembersUpdate.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Discord.API.Gateway +{ + internal class ThreadMembersUpdated + { + [JsonProperty("id")] + public ulong Id { get; set; } + + [JsonProperty("guild_id")] + public ulong GuildId { get; set; } + + [JsonProperty("member_count")] + public int MemberCount { get; set; } + + [JsonProperty("added_members")] + public Optional AddedMembers { get; set; } + + [JsonProperty("removed_member_ids")] + public Optional RemovedMemberIds { get; set; } + } +} diff --git a/src/Discord.Net.WebSocket/API/Gateway/TypingStartEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/TypingStartEvent.cs index 5ceae4b7a..729ea176f 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/TypingStartEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/TypingStartEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/VoiceServerUpdateEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/VoiceServerUpdateEvent.cs index 29167c1cc..8df3f0108 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/VoiceServerUpdateEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/VoiceServerUpdateEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/VoiceStateUpdateParams.cs b/src/Discord.Net.WebSocket/API/Gateway/VoiceStateUpdateParams.cs index 521160126..ad21b14f1 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/VoiceStateUpdateParams.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/VoiceStateUpdateParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/Gateway/WebhookUpdateEvent.cs b/src/Discord.Net.WebSocket/API/Gateway/WebhookUpdateEvent.cs index e5c7afe41..c1e6d5385 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/WebhookUpdateEvent.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/WebhookUpdateEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Gateway diff --git a/src/Discord.Net.WebSocket/API/SocketFrame.cs b/src/Discord.Net.WebSocket/API/SocketFrame.cs index fae741432..11c82ec44 100644 --- a/src/Discord.Net.WebSocket/API/SocketFrame.cs +++ b/src/Discord.Net.WebSocket/API/SocketFrame.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API diff --git a/src/Discord.Net.WebSocket/API/Voice/IdentifyParams.cs b/src/Discord.Net.WebSocket/API/Voice/IdentifyParams.cs index d446867e1..508b70d70 100644 --- a/src/Discord.Net.WebSocket/API/Voice/IdentifyParams.cs +++ b/src/Discord.Net.WebSocket/API/Voice/IdentifyParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Voice diff --git a/src/Discord.Net.WebSocket/API/Voice/ReadyEvent.cs b/src/Discord.Net.WebSocket/API/Voice/ReadyEvent.cs index 7188cd8f7..fb910573a 100644 --- a/src/Discord.Net.WebSocket/API/Voice/ReadyEvent.cs +++ b/src/Discord.Net.WebSocket/API/Voice/ReadyEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; using System; @@ -15,7 +14,7 @@ internal class ReadyEvent [JsonProperty("modes")] public string[] Modes { get; set; } [JsonProperty("heartbeat_interval")] - [Obsolete("This field is errorneous and should not be used", true)] + [Obsolete("This field is erroneous and should not be used", true)] public int HeartbeatInterval { get; set; } } } diff --git a/src/Discord.Net.WebSocket/API/Voice/SelectProtocolParams.cs b/src/Discord.Net.WebSocket/API/Voice/SelectProtocolParams.cs index 8c577e5b5..2e9bd157a 100644 --- a/src/Discord.Net.WebSocket/API/Voice/SelectProtocolParams.cs +++ b/src/Discord.Net.WebSocket/API/Voice/SelectProtocolParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Voice diff --git a/src/Discord.Net.WebSocket/API/Voice/SessionDescriptionEvent.cs b/src/Discord.Net.WebSocket/API/Voice/SessionDescriptionEvent.cs index 45befadcf..043b9fe86 100644 --- a/src/Discord.Net.WebSocket/API/Voice/SessionDescriptionEvent.cs +++ b/src/Discord.Net.WebSocket/API/Voice/SessionDescriptionEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Voice diff --git a/src/Discord.Net.WebSocket/API/Voice/SpeakingEvent.cs b/src/Discord.Net.WebSocket/API/Voice/SpeakingEvent.cs index 0272a8f53..c1746e9ce 100644 --- a/src/Discord.Net.WebSocket/API/Voice/SpeakingEvent.cs +++ b/src/Discord.Net.WebSocket/API/Voice/SpeakingEvent.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Voice diff --git a/src/Discord.Net.WebSocket/API/Voice/SpeakingParams.cs b/src/Discord.Net.WebSocket/API/Voice/SpeakingParams.cs index abdf90667..e03bfc751 100644 --- a/src/Discord.Net.WebSocket/API/Voice/SpeakingParams.cs +++ b/src/Discord.Net.WebSocket/API/Voice/SpeakingParams.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Voice diff --git a/src/Discord.Net.WebSocket/API/Voice/UdpProtocolInfo.cs b/src/Discord.Net.WebSocket/API/Voice/UdpProtocolInfo.cs index 6f4719e7e..5e69a0370 100644 --- a/src/Discord.Net.WebSocket/API/Voice/UdpProtocolInfo.cs +++ b/src/Discord.Net.WebSocket/API/Voice/UdpProtocolInfo.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API.Voice diff --git a/src/Discord.Net.WebSocket/API/Voice/VoiceCloseCode.cs b/src/Discord.Net.WebSocket/API/Voice/VoiceCloseCode.cs new file mode 100644 index 000000000..e35227050 --- /dev/null +++ b/src/Discord.Net.WebSocket/API/Voice/VoiceCloseCode.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.API.Voice +{ + /// + /// Represents generic op codes for voice disconnect. + /// + public enum VoiceCloseCode + { + /// + /// You sent an invalid opcode. + /// + UnknownOpcode = 4001, + /// + /// You sent an invalid payload in your identifying to the Gateway. + /// + DecodeFailure = 4002, + /// + /// You sent a payload before identifying with the Gateway. + /// + NotAuthenticated = 4003, + /// + /// The token you sent in your identify payload is incorrect. + /// + AuthenticationFailed = 4004, + /// + /// You sent more than one identify payload. Stahp. + /// + AlreadyAuthenticated = 4005, + /// + /// Your session is no longer valid. + /// + SessionNolongerValid = 4006, + /// + /// Your session has timed out. + /// + SessionTimeout = 4009, + /// + /// We can't find the server you're trying to connect to. + /// + ServerNotFound = 4011, + /// + /// We didn't recognize the protocol you sent. + /// + UnknownProtocol = 4012, + /// + /// Channel was deleted, you were kicked, voice server changed, or the main gateway session was dropped. Should not reconnect. + /// + Disconnected = 4014, + /// + /// The server crashed. Our bad! Try resuming. + /// + VoiceServerCrashed = 4015, + /// + /// We didn't recognize your encryption. + /// + UnknownEncryptionMode = 4016, + } +} diff --git a/src/Discord.Net.WebSocket/API/Voice/VoiceOpCode.cs b/src/Discord.Net.WebSocket/API/Voice/VoiceOpCode.cs index 67afe6173..94006505a 100644 --- a/src/Discord.Net.WebSocket/API/Voice/VoiceOpCode.cs +++ b/src/Discord.Net.WebSocket/API/Voice/VoiceOpCode.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 namespace Discord.API.Voice { internal enum VoiceOpCode : byte diff --git a/src/Discord.Net.WebSocket/Audio/Streams/BufferedWriteStream.cs b/src/Discord.Net.WebSocket/Audio/Streams/BufferedWriteStream.cs index a2de252a2..25afde784 100644 --- a/src/Discord.Net.WebSocket/Audio/Streams/BufferedWriteStream.cs +++ b/src/Discord.Net.WebSocket/Audio/Streams/BufferedWriteStream.cs @@ -125,7 +125,7 @@ private Task Run() timestamp += OpusEncoder.FrameSamplesPerChannel; } #if DEBUG - var _ = _logger?.DebugAsync("Buffer underrun"); + var _ = _logger?.DebugAsync("Buffer under run"); #endif } } diff --git a/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs b/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs index fcaa793fc..4ad25d4d5 100644 --- a/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs +++ b/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs @@ -1,3 +1,4 @@ +using Discord.Rest; using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -6,7 +7,7 @@ namespace Discord.WebSocket { public partial class BaseSocketClient { - //Channels + #region Channels /// Fired when a channel is created. /// /// @@ -23,7 +24,7 @@ public partial class BaseSocketClient /// /// - public event Func ChannelCreated + public event Func ChannelCreated { add { _channelCreatedEvent.Add(value); } remove { _channelCreatedEvent.Remove(value); } @@ -45,7 +46,8 @@ public event Func ChannelCreated /// /// - public event Func ChannelDestroyed { + public event Func ChannelDestroyed + { add { _channelDestroyedEvent.Add(value); } remove { _channelDestroyedEvent.Remove(value); } } @@ -67,13 +69,15 @@ public event Func ChannelDestroyed { /// /// - public event Func ChannelUpdated { + public event Func ChannelUpdated + { add { _channelUpdatedEvent.Add(value); } remove { _channelUpdatedEvent.Remove(value); } - } + } internal readonly AsyncEvent> _channelUpdatedEvent = new AsyncEvent>(); + #endregion - //Messages + #region Messages /// Fired when a message is received. /// /// @@ -92,7 +96,8 @@ public event Func ChannelUpdated { /// /// - public event Func MessageReceived { + public event Func MessageReceived + { add { _messageReceivedEvent.Add(value); } remove { _messageReceivedEvent.Remove(value); } } @@ -124,7 +129,9 @@ public event Func MessageReceived { /// /// - public event Func, Cacheable, Task> MessageDeleted { + + public event Func, Cacheable, Task> MessageDeleted + { add { _messageDeletedEvent.Add(value); } remove { _messageDeletedEvent.Remove(value); } } @@ -182,7 +189,8 @@ public event Func>, Cacheable parameter. /// /// - public event Func, SocketMessage, ISocketMessageChannel, Task> MessageUpdated { + public event Func, SocketMessage, ISocketMessageChannel, Task> MessageUpdated + { add { _messageUpdatedEvent.Add(value); } remove { _messageUpdatedEvent.Remove(value); } } @@ -217,19 +225,22 @@ public event Func, SocketMessage, ISocketMessageChann /// /// - public event Func, Cacheable, SocketReaction, Task> ReactionAdded { + public event Func, Cacheable, SocketReaction, Task> ReactionAdded + { add { _reactionAddedEvent.Add(value); } remove { _reactionAddedEvent.Remove(value); } } internal readonly AsyncEvent, Cacheable, SocketReaction, Task>> _reactionAddedEvent = new AsyncEvent, Cacheable, SocketReaction, Task>>(); /// Fired when a reaction is removed from a message. - public event Func, Cacheable, SocketReaction, Task> ReactionRemoved { + public event Func, Cacheable, SocketReaction, Task> ReactionRemoved + { add { _reactionRemovedEvent.Add(value); } remove { _reactionRemovedEvent.Remove(value); } } internal readonly AsyncEvent, Cacheable, SocketReaction, Task>> _reactionRemovedEvent = new AsyncEvent, Cacheable, SocketReaction, Task>>(); /// Fired when all reactions to a message are cleared. - public event Func, Cacheable, Task> ReactionsCleared { + public event Func, Cacheable, Task> ReactionsCleared + { add { _reactionsClearedEvent.Add(value); } remove { _reactionsClearedEvent.Remove(value); } } @@ -256,104 +267,200 @@ public event Func, Cacheable, Cacheable, IEmote, Task>> _reactionsRemovedForEmoteEvent = new AsyncEvent, Cacheable, IEmote, Task>>(); + #endregion - //Roles + #region Roles /// Fired when a role is created. - public event Func RoleCreated { + public event Func RoleCreated + { add { _roleCreatedEvent.Add(value); } remove { _roleCreatedEvent.Remove(value); } } internal readonly AsyncEvent> _roleCreatedEvent = new AsyncEvent>(); /// Fired when a role is deleted. - public event Func RoleDeleted { + public event Func RoleDeleted + { add { _roleDeletedEvent.Add(value); } remove { _roleDeletedEvent.Remove(value); } } internal readonly AsyncEvent> _roleDeletedEvent = new AsyncEvent>(); /// Fired when a role is updated. - public event Func RoleUpdated { + public event Func RoleUpdated + { add { _roleUpdatedEvent.Add(value); } remove { _roleUpdatedEvent.Remove(value); } } internal readonly AsyncEvent> _roleUpdatedEvent = new AsyncEvent>(); + #endregion - //Guilds + #region Guilds /// Fired when the connected account joins a guild. - public event Func JoinedGuild { + public event Func JoinedGuild + { add { _joinedGuildEvent.Add(value); } remove { _joinedGuildEvent.Remove(value); } } internal readonly AsyncEvent> _joinedGuildEvent = new AsyncEvent>(); /// Fired when the connected account leaves a guild. - public event Func LeftGuild { + public event Func LeftGuild + { add { _leftGuildEvent.Add(value); } remove { _leftGuildEvent.Remove(value); } } internal readonly AsyncEvent> _leftGuildEvent = new AsyncEvent>(); /// Fired when a guild becomes available. - public event Func GuildAvailable { + public event Func GuildAvailable + { add { _guildAvailableEvent.Add(value); } remove { _guildAvailableEvent.Remove(value); } } internal readonly AsyncEvent> _guildAvailableEvent = new AsyncEvent>(); /// Fired when a guild becomes unavailable. - public event Func GuildUnavailable { + public event Func GuildUnavailable + { add { _guildUnavailableEvent.Add(value); } remove { _guildUnavailableEvent.Remove(value); } } internal readonly AsyncEvent> _guildUnavailableEvent = new AsyncEvent>(); /// Fired when offline guild members are downloaded. - public event Func GuildMembersDownloaded { + public event Func GuildMembersDownloaded + { add { _guildMembersDownloadedEvent.Add(value); } remove { _guildMembersDownloadedEvent.Remove(value); } } internal readonly AsyncEvent> _guildMembersDownloadedEvent = new AsyncEvent>(); /// Fired when a guild is updated. - public event Func GuildUpdated { + public event Func GuildUpdated + { add { _guildUpdatedEvent.Add(value); } remove { _guildUpdatedEvent.Remove(value); } } internal readonly AsyncEvent> _guildUpdatedEvent = new AsyncEvent>(); + /// Fired when a user leaves without agreeing to the member screening + public event Func, SocketGuild, Task> GuildJoinRequestDeleted + { + add { _guildJoinRequestDeletedEvent.Add(value); } + remove { _guildJoinRequestDeletedEvent.Remove(value); } + } + internal readonly AsyncEvent, SocketGuild, Task>> _guildJoinRequestDeletedEvent = new AsyncEvent, SocketGuild, Task>>(); + #endregion + + #region Guild Events + + /// + /// Fired when a guild event is created. + /// + public event Func GuildScheduledEventCreated + { + add { _guildScheduledEventCreated.Add(value); } + remove { _guildScheduledEventCreated.Remove(value); } + } + internal readonly AsyncEvent> _guildScheduledEventCreated = new AsyncEvent>(); + + /// + /// Fired when a guild event is updated. + /// + public event Func, SocketGuildEvent, Task> GuildScheduledEventUpdated + { + add { _guildScheduledEventUpdated.Add(value); } + remove { _guildScheduledEventUpdated.Remove(value); } + } + internal readonly AsyncEvent, SocketGuildEvent, Task>> _guildScheduledEventUpdated = new AsyncEvent, SocketGuildEvent, Task>>(); + + + /// + /// Fired when a guild event is cancelled. + /// + public event Func GuildScheduledEventCancelled + { + add { _guildScheduledEventCancelled.Add(value); } + remove { _guildScheduledEventCancelled.Remove(value); } + } + internal readonly AsyncEvent> _guildScheduledEventCancelled = new AsyncEvent>(); + + /// + /// Fired when a guild event is completed. + /// + public event Func GuildScheduledEventCompleted + { + add { _guildScheduledEventCompleted.Add(value); } + remove { _guildScheduledEventCompleted.Remove(value); } + } + internal readonly AsyncEvent> _guildScheduledEventCompleted = new AsyncEvent>(); + + /// + /// Fired when a guild event is started. + /// + public event Func GuildScheduledEventStarted + { + add { _guildScheduledEventStarted.Add(value); } + remove { _guildScheduledEventStarted.Remove(value); } + } + internal readonly AsyncEvent> _guildScheduledEventStarted = new AsyncEvent>(); + + public event Func, SocketGuildEvent, Task> GuildScheduledEventUserAdd + { + add { _guildScheduledEventUserAdd.Add(value); } + remove { _guildScheduledEventUserAdd.Remove(value); } + } + internal readonly AsyncEvent, SocketGuildEvent, Task>> _guildScheduledEventUserAdd = new AsyncEvent, SocketGuildEvent, Task>>(); + + public event Func, SocketGuildEvent, Task> GuildScheduledEventUserRemove + { + add { _guildScheduledEventUserRemove.Add(value); } + remove { _guildScheduledEventUserRemove.Remove(value); } + } + internal readonly AsyncEvent, SocketGuildEvent, Task>> _guildScheduledEventUserRemove = new AsyncEvent, SocketGuildEvent, Task>>(); + - //Users + #endregion + + #region Users /// Fired when a user joins a guild. - public event Func UserJoined { + public event Func UserJoined + { add { _userJoinedEvent.Add(value); } remove { _userJoinedEvent.Remove(value); } } internal readonly AsyncEvent> _userJoinedEvent = new AsyncEvent>(); /// Fired when a user leaves a guild. - public event Func UserLeft { + public event Func UserLeft + { add { _userLeftEvent.Add(value); } remove { _userLeftEvent.Remove(value); } } internal readonly AsyncEvent> _userLeftEvent = new AsyncEvent>(); /// Fired when a user is banned from a guild. - public event Func UserBanned { + public event Func UserBanned + { add { _userBannedEvent.Add(value); } remove { _userBannedEvent.Remove(value); } } internal readonly AsyncEvent> _userBannedEvent = new AsyncEvent>(); /// Fired when a user is unbanned from a guild. - public event Func UserUnbanned { + public event Func UserUnbanned + { add { _userUnbannedEvent.Add(value); } remove { _userUnbannedEvent.Remove(value); } } internal readonly AsyncEvent> _userUnbannedEvent = new AsyncEvent>(); /// Fired when a user is updated. - public event Func UserUpdated { + public event Func UserUpdated + { add { _userUpdatedEvent.Add(value); } remove { _userUpdatedEvent.Remove(value); } } internal readonly AsyncEvent> _userUpdatedEvent = new AsyncEvent>(); /// Fired when a guild member is updated, or a member presence is updated. - public event Func, SocketGuildUser, Task> GuildMemberUpdated { + public event Func, SocketGuildUser, Task> GuildMemberUpdated + { add { _guildMemberUpdatedEvent.Add(value); } remove { _guildMemberUpdatedEvent.Remove(value); } } - internal readonly AsyncEvent, SocketGuildUser, Task>> _guildMemberUpdatedEvent = new AsyncEvent, SocketGuildUser, Task>>(); + internal readonly AsyncEvent, SocketGuildUser, Task>> _guildMemberUpdatedEvent = new AsyncEvent, SocketGuildUser, Task>>(); /// Fired when a user joins, leaves, or moves voice channels. - public event Func UserVoiceStateUpdated { + public event Func UserVoiceStateUpdated + { add { _userVoiceStateUpdatedEvent.Add(value); } remove { _userVoiceStateUpdatedEvent.Remove(value); } } @@ -361,36 +468,41 @@ public event Func UserVoic /// Fired when the bot connects to a Discord voice server. public event Func VoiceServerUpdated { - add { _voiceServerUpdatedEvent.Add(value); } + add { _voiceServerUpdatedEvent.Add(value); } remove { _voiceServerUpdatedEvent.Remove(value); } } internal readonly AsyncEvent> _voiceServerUpdatedEvent = new AsyncEvent>(); /// Fired when the connected account is updated. - public event Func CurrentUserUpdated { + public event Func CurrentUserUpdated + { add { _selfUpdatedEvent.Add(value); } remove { _selfUpdatedEvent.Remove(value); } } internal readonly AsyncEvent> _selfUpdatedEvent = new AsyncEvent>(); /// Fired when a user starts typing. - public event Func, Cacheable, Task> UserIsTyping { + public event Func, Cacheable, Task> UserIsTyping + { add { _userIsTypingEvent.Add(value); } remove { _userIsTypingEvent.Remove(value); } } internal readonly AsyncEvent, Cacheable, Task>> _userIsTypingEvent = new AsyncEvent, Cacheable, Task>>(); /// Fired when a user joins a group channel. - public event Func RecipientAdded { + public event Func RecipientAdded + { add { _recipientAddedEvent.Add(value); } remove { _recipientAddedEvent.Remove(value); } } internal readonly AsyncEvent> _recipientAddedEvent = new AsyncEvent>(); /// Fired when a user is removed from a group channel. - public event Func RecipientRemoved { + public event Func RecipientRemoved + { add { _recipientRemovedEvent.Add(value); } remove { _recipientRemovedEvent.Remove(value); } } internal readonly AsyncEvent> _recipientRemovedEvent = new AsyncEvent>(); + #endregion - //Invites + #region Invites /// /// Fired when an invite is created. /// @@ -431,5 +543,292 @@ public event Func InviteDeleted remove { _inviteDeletedEvent.Remove(value); } } internal readonly AsyncEvent> _inviteDeletedEvent = new AsyncEvent>(); + #endregion + + #region Interactions + /// + /// Fired when an Interaction is created. This event covers all types of interactions including but not limited to: buttons, select menus, slash commands, autocompletes. + /// + /// + /// + /// This event is fired when an interaction is created. The event handler must return a + /// and accept a as its parameter. + /// + /// + /// The interaction created will be passed into the parameter. + /// + /// + public event Func InteractionCreated + { + add { _interactionCreatedEvent.Add(value); } + remove { _interactionCreatedEvent.Remove(value); } + } + internal readonly AsyncEvent> _interactionCreatedEvent = new AsyncEvent>(); + + /// + /// Fired when a button is clicked and its interaction is received. + /// + public event Func ButtonExecuted + { + add => _buttonExecuted.Add(value); + remove => _buttonExecuted.Remove(value); + } + internal readonly AsyncEvent> _buttonExecuted = new AsyncEvent>(); + + /// + /// Fired when a select menu is used and its interaction is received. + /// + public event Func SelectMenuExecuted + { + add => _selectMenuExecuted.Add(value); + remove => _selectMenuExecuted.Remove(value); + } + internal readonly AsyncEvent> _selectMenuExecuted = new AsyncEvent>(); + /// + /// Fired when a slash command is used and its interaction is received. + /// + public event Func SlashCommandExecuted + { + add => _slashCommandExecuted.Add(value); + remove => _slashCommandExecuted.Remove(value); + } + internal readonly AsyncEvent> _slashCommandExecuted = new AsyncEvent>(); + + /// + /// Fired when a user command is used and its interaction is received. + /// + public event Func UserCommandExecuted + { + add => _userCommandExecuted.Add(value); + remove => _userCommandExecuted.Remove(value); + } + internal readonly AsyncEvent> _userCommandExecuted = new AsyncEvent>(); + + /// + /// Fired when a message command is used and its interaction is received. + /// + public event Func MessageCommandExecuted + { + add => _messageCommandExecuted.Add(value); + remove => _messageCommandExecuted.Remove(value); + } + internal readonly AsyncEvent> _messageCommandExecuted = new AsyncEvent>(); + /// + /// Fired when an autocomplete is used and its interaction is received. + /// + public event Func AutocompleteExecuted + { + add => _autocompleteExecuted.Add(value); + remove => _autocompleteExecuted.Remove(value); + } + internal readonly AsyncEvent> _autocompleteExecuted = new AsyncEvent>(); + + /// + /// Fired when a guild application command is created. + /// + /// + /// + /// This event is fired when an application command is created. The event handler must return a + /// and accept a as its parameter. + /// + /// + /// The command that was deleted will be passed into the parameter. + /// + /// + /// This event is an undocumented discord event and may break at any time, its not recommended to rely on this event + /// + /// + public event Func ApplicationCommandCreated + { + add { _applicationCommandCreated.Add(value); } + remove { _applicationCommandCreated.Remove(value); } + } + internal readonly AsyncEvent> _applicationCommandCreated = new AsyncEvent>(); + + /// + /// Fired when a guild application command is updated. + /// + /// + /// + /// This event is fired when an application command is updated. The event handler must return a + /// and accept a as its parameter. + /// + /// + /// The command that was deleted will be passed into the parameter. + /// + /// + /// This event is an undocumented discord event and may break at any time, its not recommended to rely on this event + /// + /// + public event Func ApplicationCommandUpdated + { + add { _applicationCommandUpdated.Add(value); } + remove { _applicationCommandUpdated.Remove(value); } + } + internal readonly AsyncEvent> _applicationCommandUpdated = new AsyncEvent>(); + + /// + /// Fired when a guild application command is deleted. + /// + /// + /// + /// This event is fired when an application command is deleted. The event handler must return a + /// and accept a as its parameter. + /// + /// + /// The command that was deleted will be passed into the parameter. + /// + /// + /// This event is an undocumented discord event and may break at any time, its not recommended to rely on this event + /// + /// + public event Func ApplicationCommandDeleted + { + add { _applicationCommandDeleted.Add(value); } + remove { _applicationCommandDeleted.Remove(value); } + } + internal readonly AsyncEvent> _applicationCommandDeleted = new AsyncEvent>(); + + /// + /// Fired when a thread is created within a guild, or when the current user is added to a thread. + /// + public event Func ThreadCreated + { + add { _threadCreated.Add(value); } + remove { _threadCreated.Remove(value); } + } + internal readonly AsyncEvent> _threadCreated = new AsyncEvent>(); + + /// + /// Fired when a thread is updated within a guild. + /// + public event Func, SocketThreadChannel, Task> ThreadUpdated + { + add { _threadUpdated.Add(value); } + remove { _threadUpdated.Remove(value); } + } + + internal readonly AsyncEvent, SocketThreadChannel, Task>> _threadUpdated = new(); + + /// + /// Fired when a thread is deleted. + /// + public event Func, Task> ThreadDeleted + { + add { _threadDeleted.Add(value); } + remove { _threadDeleted.Remove(value); } + } + internal readonly AsyncEvent, Task>> _threadDeleted = new AsyncEvent, Task>>(); + + /// + /// Fired when a user joins a thread + /// + public event Func ThreadMemberJoined + { + add { _threadMemberJoined.Add(value); } + remove { _threadMemberJoined.Remove(value); } + } + internal readonly AsyncEvent> _threadMemberJoined = new AsyncEvent>(); + + /// + /// Fired when a user leaves a thread + /// + public event Func ThreadMemberLeft + { + add { _threadMemberLeft.Add(value); } + remove { _threadMemberLeft.Remove(value); } + } + internal readonly AsyncEvent> _threadMemberLeft = new AsyncEvent>(); + + /// + /// Fired when a stage is started. + /// + public event Func StageStarted + { + add { _stageStarted.Add(value); } + remove { _stageStarted.Remove(value); } + } + internal readonly AsyncEvent> _stageStarted = new AsyncEvent>(); + + /// + /// Fired when a stage ends. + /// + public event Func StageEnded + { + add { _stageEnded.Add(value); } + remove { _stageEnded.Remove(value); } + } + internal readonly AsyncEvent> _stageEnded = new AsyncEvent>(); + + /// + /// Fired when a stage is updated. + /// + public event Func StageUpdated + { + add { _stageUpdated.Add(value); } + remove { _stageUpdated.Remove(value); } + } + internal readonly AsyncEvent> _stageUpdated = new AsyncEvent>(); + + /// + /// Fired when a user requests to speak within a stage channel. + /// + public event Func RequestToSpeak + { + add { _requestToSpeak.Add(value); } + remove { _requestToSpeak.Remove(value); } + } + internal readonly AsyncEvent> _requestToSpeak = new AsyncEvent>(); + + /// + /// Fired when a speaker is added in a stage channel. + /// + public event Func SpeakerAdded + { + add { _speakerAdded.Add(value); } + remove { _speakerAdded.Remove(value); } + } + internal readonly AsyncEvent> _speakerAdded = new AsyncEvent>(); + + /// + /// Fired when a speaker is removed from a stage channel. + /// + public event Func SpeakerRemoved + { + add { _speakerRemoved.Add(value); } + remove { _speakerRemoved.Remove(value); } + } + internal readonly AsyncEvent> _speakerRemoved = new AsyncEvent>(); + + /// + /// Fired when a sticker in a guild is created. + /// + public event Func GuildStickerCreated + { + add { _guildStickerCreated.Add(value); } + remove { _guildStickerCreated.Remove(value); } + } + internal readonly AsyncEvent> _guildStickerCreated = new AsyncEvent>(); + + /// + /// Fired when a sticker in a guild is updated. + /// + public event Func GuildStickerUpdated + { + add { _guildStickerUpdated.Add(value); } + remove { _guildStickerUpdated.Remove(value); } + } + internal readonly AsyncEvent> _guildStickerUpdated = new AsyncEvent>(); + + /// + /// Fired when a sticker in a guild is deleted. + /// + public event Func GuildStickerDeleted + { + add { _guildStickerDeleted.Add(value); } + remove { _guildStickerDeleted.Remove(value); } + } + internal readonly AsyncEvent> _guildStickerDeleted = new AsyncEvent>(); + #endregion } } diff --git a/src/Discord.Net.WebSocket/BaseSocketClient.cs b/src/Discord.Net.WebSocket/BaseSocketClient.cs index 1cfe6c8bf..9e25ab382 100644 --- a/src/Discord.Net.WebSocket/BaseSocketClient.cs +++ b/src/Discord.Net.WebSocket/BaseSocketClient.cs @@ -12,6 +12,7 @@ namespace Discord.WebSocket /// public abstract partial class BaseSocketClient : BaseDiscordClient, IDiscordClient { + #region BaseSocketClient protected readonly DiscordSocketConfig BaseConfig; /// @@ -44,6 +45,10 @@ public abstract partial class BaseSocketClient : BaseDiscordClient, IDiscordClie internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; + /// + /// Gets a collection of default stickers. + /// + public abstract IReadOnlyCollection> DefaultStickerPacks { get; } /// /// Gets the current logged-in user. /// @@ -75,7 +80,7 @@ internal BaseSocketClient(DiscordSocketConfig config, DiscordRestApiClient clien : base(config, client) => BaseConfig = config; private static DiscordSocketApiClient CreateApiClient(DiscordSocketConfig config) => new DiscordSocketApiClient(config.RestClientProvider, config.WebSocketProvider, DiscordRestConfig.UserAgent, - useSystemClock: config.UseSystemClock); + useSystemClock: config.UseSystemClock); /// /// Gets a Discord application information for the logged-in user. @@ -268,8 +273,19 @@ public Task> GetConnectionsAsync(RequestOpti /// public Task GetInviteAsync(string inviteId, RequestOptions options = null) => ClientHelper.GetInviteAsync(this, inviteId, options ?? RequestOptions.Default); - - // IDiscordClient + /// + /// Gets a sticker. + /// + /// Whether or not to allow downloading from the api. + /// The id of the sticker to get. + /// The options to be used when sending the request. + /// + /// A if found, otherwise . + /// + public abstract Task GetStickerAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); +#endregion + + #region IDiscordClient /// async Task IDiscordClient.GetApplicationInfoAsync(RequestOptions options) => await GetApplicationInfoAsync(options).ConfigureAwait(false); @@ -317,5 +333,6 @@ async Task> IDiscordClient.GetVoiceRegionsAsyn { return await GetVoiceRegionsAsync().ConfigureAwait(false); } + #endregion } } diff --git a/src/Discord.Net.WebSocket/ClientState.cs b/src/Discord.Net.WebSocket/ClientState.cs index f2e370d02..7129feb48 100644 --- a/src/Discord.Net.WebSocket/ClientState.cs +++ b/src/Discord.Net.WebSocket/ClientState.cs @@ -16,12 +16,14 @@ internal class ClientState private readonly ConcurrentDictionary _guilds; private readonly ConcurrentDictionary _users; private readonly ConcurrentHashSet _groupChannels; + private readonly ConcurrentDictionary _commands; internal IReadOnlyCollection Channels => _channels.ToReadOnlyCollection(); internal IReadOnlyCollection DMChannels => _dmChannels.ToReadOnlyCollection(); internal IReadOnlyCollection GroupChannels => _groupChannels.Select(x => GetChannel(x) as SocketGroupChannel).ToReadOnlyCollection(_groupChannels); internal IReadOnlyCollection Guilds => _guilds.ToReadOnlyCollection(); internal IReadOnlyCollection Users => _users.ToReadOnlyCollection(); + internal IReadOnlyCollection Commands => _commands.ToReadOnlyCollection(); internal IReadOnlyCollection PrivateChannels => _dmChannels.Select(x => x.Value as ISocketPrivateChannel).Concat( @@ -37,6 +39,7 @@ public ClientState(int guildCount, int dmChannelCount) _guilds = new ConcurrentDictionary(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(guildCount * CollectionMultiplier)); _users = new ConcurrentDictionary(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(estimatedUsersCount * CollectionMultiplier)); _groupChannels = new ConcurrentHashSet(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(10 * CollectionMultiplier)); + _commands = new ConcurrentDictionary(); } internal SocketChannel GetChannel(ulong id) @@ -139,5 +142,33 @@ internal void PurgeUsers() foreach (var guild in _guilds.Values) guild.PurgeGuildUserCache(); } + + internal SocketApplicationCommand GetCommand(ulong id) + { + if (_commands.TryGetValue(id, out SocketApplicationCommand command)) + return command; + return null; + } + internal void AddCommand(SocketApplicationCommand command) + { + _commands[command.Id] = command; + } + internal SocketApplicationCommand GetOrAddCommand(ulong id, Func commandFactory) + { + return _commands.GetOrAdd(id, commandFactory); + } + internal SocketApplicationCommand RemoveCommand(ulong id) + { + if (_commands.TryRemove(id, out SocketApplicationCommand command)) + return command; + return null; + } + internal void PurgeCommands(Func precondition) + { + var ids = _commands.Where(x => precondition(x.Value)).Select(x => x.Key); + + foreach (var id in ids) + _commands.TryRemove(id, out var _); + } } } diff --git a/src/Discord.Net.WebSocket/Commands/ShardedCommandContext.cs b/src/Discord.Net.WebSocket/Commands/ShardedCommandContext.cs index f970c32fc..905cd01a1 100644 --- a/src/Discord.Net.WebSocket/Commands/ShardedCommandContext.cs +++ b/src/Discord.Net.WebSocket/Commands/ShardedCommandContext.cs @@ -5,6 +5,7 @@ namespace Discord.Commands /// The sharded variant of , which may contain the client, user, guild, channel, and message. public class ShardedCommandContext : SocketCommandContext, ICommandContext { + #region ShardedCommandContext /// Gets the that the command is executed with. public new DiscordShardedClient Client { get; } @@ -17,9 +18,11 @@ public ShardedCommandContext(DiscordShardedClient client, SocketUserMessage msg) /// Gets the shard ID of the command context. private static int GetShardId(DiscordShardedClient client, IGuild guild) => guild == null ? 0 : client.GetShardIdFor(guild); +#endregion - //ICommandContext + #region ICommandContext /// IDiscordClient ICommandContext.Client => Client; + #endregion } } diff --git a/src/Discord.Net.WebSocket/Commands/SocketCommandContext.cs b/src/Discord.Net.WebSocket/Commands/SocketCommandContext.cs index f4d517909..d7180873b 100644 --- a/src/Discord.Net.WebSocket/Commands/SocketCommandContext.cs +++ b/src/Discord.Net.WebSocket/Commands/SocketCommandContext.cs @@ -7,6 +7,7 @@ namespace Discord.Commands /// public class SocketCommandContext : ICommandContext { + #region SocketCommandContext /// /// Gets the that the command is executed with. /// @@ -46,8 +47,9 @@ public SocketCommandContext(DiscordSocketClient client, SocketUserMessage msg) User = msg.Author; Message = msg; } +#endregion - //ICommandContext + #region ICommandContext /// IDiscordClient ICommandContext.Client => Client; /// @@ -58,5 +60,6 @@ public SocketCommandContext(DiscordSocketClient client, SocketUserMessage msg) IUser ICommandContext.User => User; /// IUserMessage ICommandContext.Message => Message; + #endregion } } diff --git a/src/Discord.Net.WebSocket/ConnectionManager.cs b/src/Discord.Net.WebSocket/ConnectionManager.cs index e444f359f..f304d4ea8 100644 --- a/src/Discord.Net.WebSocket/ConnectionManager.cs +++ b/src/Discord.Net.WebSocket/ConnectionManager.cs @@ -57,6 +57,9 @@ internal ConnectionManager(SemaphoreSlim stateLock, Logger logger, int connectio public virtual async Task StartAsync() { + if (State != ConnectionState.Disconnected) + throw new InvalidOperationException("Cannot start an already running client."); + await AcquireConnectionLock().ConfigureAwait(false); var reconnectCancelToken = new CancellationTokenSource(); _reconnectCancelToken?.Dispose(); diff --git a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj index 01aece130..4121e7d00 100644 --- a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj +++ b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj @@ -1,4 +1,4 @@ - + @@ -13,4 +13,4 @@ - + \ No newline at end of file diff --git a/src/Discord.Net.WebSocket/DiscordShardedClient.Events.cs b/src/Discord.Net.WebSocket/DiscordShardedClient.Events.cs index c9e679669..50230572c 100644 --- a/src/Discord.Net.WebSocket/DiscordShardedClient.Events.cs +++ b/src/Discord.Net.WebSocket/DiscordShardedClient.Events.cs @@ -1,11 +1,11 @@ -using System; +using System; using System.Threading.Tasks; namespace Discord.WebSocket { public partial class DiscordShardedClient { - //General + #region General /// Fired when a shard is connected to the Discord gateway. public event Func ShardConnected { @@ -34,5 +34,6 @@ public event Func ShardLatencyUpdated remove { _shardLatencyUpdatedEvent.Remove(value); } } private readonly AsyncEvent> _shardLatencyUpdatedEvent = new AsyncEvent>(); + #endregion } -} \ No newline at end of file +} diff --git a/src/Discord.Net.WebSocket/DiscordShardedClient.cs b/src/Discord.Net.WebSocket/DiscordShardedClient.cs index e6d05b525..307f9a009 100644 --- a/src/Discord.Net.WebSocket/DiscordShardedClient.cs +++ b/src/Discord.Net.WebSocket/DiscordShardedClient.cs @@ -6,16 +6,19 @@ using System.Linq; using System.Threading.Tasks; using System.Threading; +using System.Collections.Immutable; namespace Discord.WebSocket { public partial class DiscordShardedClient : BaseSocketClient, IDiscordClient { + #region DiscordShardedClient private readonly DiscordSocketConfig _baseConfig; private readonly Dictionary _shardIdsToIndex; private readonly bool _automaticShards; private int[] _shardIds; private DiscordSocketClient[] _shards; + private ImmutableArray> _defaultStickers; private int _totalShards; private SemaphoreSlim[] _identifySemaphores; private object _semaphoreResetLock; @@ -30,7 +33,20 @@ public partial class DiscordShardedClient : BaseSocketClient, IDiscordClient /// public override IActivity Activity { get => _shards[0].Activity; protected set { } } - internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; + internal new DiscordSocketApiClient ApiClient + { + get + { + if (base.ApiClient.CurrentUserId == null) + base.ApiClient.CurrentUserId = CurrentUser?.Id; + + return base.ApiClient; + } + } + /// + public override IReadOnlyCollection> DefaultStickerPacks + => _defaultStickers.ToReadOnlyCollection(); + /// public override IReadOnlyCollection Guilds => GetGuilds().ToReadOnlyCollection(GetGuildCount); /// @@ -68,6 +84,7 @@ private DiscordShardedClient(int[] ids, DiscordSocketConfig config, API.DiscordS _shardIdsToIndex = new Dictionary(); config.DisplayInitialLog = false; _baseConfig = config; + _defaultStickers = ImmutableArray.Create>(); if (config.TotalShards == null) _automaticShards = true; @@ -146,6 +163,10 @@ internal override async Task OnLoginAsync(TokenType tokenType, string token) //Assume thread safe: already in a connection lock for (int i = 0; i < _shards.Length; i++) await _shards[i].LoginAsync(tokenType, token); + + if(_defaultStickers.Length == 0 && _baseConfig.AlwaysDownloadDefaultStickers) + await DownloadDefaultStickersAsync().ConfigureAwait(false); + } internal override async Task OnLogoutAsync() { @@ -238,6 +259,67 @@ private int GetGuildCount() result += _shards[i].Guilds.Count; return result; } + /// + public override async Task GetStickerAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) + { + var sticker = _defaultStickers.FirstOrDefault(x => x.Stickers.Any(y => y.Id == id))?.Stickers.FirstOrDefault(x => x.Id == id); + + if (sticker != null) + return sticker; + + foreach (var guild in Guilds) + { + sticker = await guild.GetStickerAsync(id, CacheMode.CacheOnly).ConfigureAwait(false); + + if (sticker != null) + return sticker; + } + + if (mode == CacheMode.CacheOnly) + return null; + + var model = await ApiClient.GetStickerAsync(id, options).ConfigureAwait(false); + + if (model == null) + return null; + + + if (model.GuildId.IsSpecified) + { + var guild = GetGuild(model.GuildId.Value); + sticker = guild.AddOrUpdateSticker(model); + return sticker; + } + else + { + return SocketSticker.Create(_shards[0], model); + } + } + private async Task DownloadDefaultStickersAsync() + { + var models = await ApiClient.ListNitroStickerPacksAsync().ConfigureAwait(false); + + var builder = ImmutableArray.CreateBuilder>(); + + foreach (var model in models.StickerPacks) + { + var stickers = model.Stickers.Select(x => SocketSticker.Create(_shards[0], x)); + + var pack = new StickerPack( + model.Name, + model.Id, + model.SkuId, + model.CoverStickerId.ToNullable(), + model.Description, + model.BannerAssetId, + stickers + ); + + builder.Add(pack); + } + + _defaultStickers = builder.ToImmutable(); + } /// public override SocketUser GetUser(ulong id) @@ -377,9 +459,45 @@ private void RegisterEvents(DiscordSocketClient client, bool isPrimary) client.InviteCreated += (invite) => _inviteCreatedEvent.InvokeAsync(invite); client.InviteDeleted += (channel, invite) => _inviteDeletedEvent.InvokeAsync(channel, invite); + + client.InteractionCreated += (interaction) => _interactionCreatedEvent.InvokeAsync(interaction); + client.ButtonExecuted += (arg) => _buttonExecuted.InvokeAsync(arg); + client.SelectMenuExecuted += (arg) => _selectMenuExecuted.InvokeAsync(arg); + client.SlashCommandExecuted += (arg) => _slashCommandExecuted.InvokeAsync(arg); + client.UserCommandExecuted += (arg) => _userCommandExecuted.InvokeAsync(arg); + client.MessageCommandExecuted += (arg) => _messageCommandExecuted.InvokeAsync(arg); + client.AutocompleteExecuted += (arg) => _autocompleteExecuted.InvokeAsync(arg); + + client.ThreadUpdated += (thread1, thread2) => _threadUpdated.InvokeAsync(thread1, thread2); + client.ThreadCreated += (thread) => _threadCreated.InvokeAsync(thread); + client.ThreadDeleted += (thread) => _threadDeleted.InvokeAsync(thread); + + client.ThreadMemberJoined += (user) => _threadMemberJoined.InvokeAsync(user); + client.ThreadMemberLeft += (user) => _threadMemberLeft.InvokeAsync(user); + client.StageEnded += (stage) => _stageEnded.InvokeAsync(stage); + client.StageStarted += (stage) => _stageStarted.InvokeAsync(stage); + client.StageUpdated += (stage1, stage2) => _stageUpdated.InvokeAsync(stage1, stage2); + + client.RequestToSpeak += (stage, user) => _requestToSpeak.InvokeAsync(stage, user); + client.SpeakerAdded += (stage, user) => _speakerAdded.InvokeAsync(stage, user); + client.SpeakerRemoved += (stage, user) => _speakerRemoved.InvokeAsync(stage, user); + + client.GuildStickerCreated += (sticker) => _guildStickerCreated.InvokeAsync(sticker); + client.GuildStickerDeleted += (sticker) => _guildStickerDeleted.InvokeAsync(sticker); + client.GuildStickerUpdated += (before, after) => _guildStickerUpdated.InvokeAsync(before, after); + client.GuildJoinRequestDeleted += (userId, guildId) => _guildJoinRequestDeletedEvent.InvokeAsync(userId, guildId); + + client.GuildScheduledEventCancelled += (arg) => _guildScheduledEventCancelled.InvokeAsync(arg); + client.GuildScheduledEventCompleted += (arg) => _guildScheduledEventCompleted.InvokeAsync(arg); + client.GuildScheduledEventCreated += (arg) => _guildScheduledEventCreated.InvokeAsync(arg); + client.GuildScheduledEventUpdated += (arg1, arg2) => _guildScheduledEventUpdated.InvokeAsync(arg1, arg2); + client.GuildScheduledEventStarted += (arg) => _guildScheduledEventStarted.InvokeAsync(arg); + client.GuildScheduledEventUserAdd += (arg1, arg2) => _guildScheduledEventUserAdd.InvokeAsync(arg1, arg2); + client.GuildScheduledEventUserRemove += (arg1, arg2) => _guildScheduledEventUserRemove.InvokeAsync(arg1, arg2); } +#endregion - //IDiscordClient + #region IDiscordClient /// async Task IDiscordClient.GetApplicationInfoAsync(RequestOptions options) => await GetApplicationInfoAsync().ConfigureAwait(false); @@ -426,7 +544,9 @@ async Task IDiscordClient.GetVoiceRegionAsync(string id, RequestOp { return await GetVoiceRegionAsync(id).ConfigureAwait(false); } + #endregion + #region Dispose internal override void Dispose(bool disposing) { if (!_isDisposed) @@ -445,5 +565,6 @@ internal override void Dispose(bool disposing) base.Dispose(disposing); } + #endregion } } diff --git a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs index 65fd23d3f..3c0f3d4a8 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketApiClient.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Discord.API.Gateway; using Discord.Net.Queue; using Discord.Net.Rest; @@ -75,8 +74,15 @@ public DiscordSocketApiClient(RestClientProvider restClientProvider, WebSocketPr using (var jsonReader = new JsonTextReader(reader)) { var msg = _serializer.Deserialize(jsonReader); + if (msg != null) + { +#if DEBUG_PACKETS + Console.WriteLine($"<- {(GatewayOpCode)msg.Operation} [{msg.Type ?? "none"}] : {(msg.Payload as Newtonsoft.Json.Linq.JToken)?.ToString().Length}"); +#endif + await _receivedGatewayEvent.InvokeAsync((GatewayOpCode)msg.Operation, msg.Sequence, msg.Type, msg.Payload).ConfigureAwait(false); + } } } }; @@ -87,11 +93,21 @@ public DiscordSocketApiClient(RestClientProvider restClientProvider, WebSocketPr { var msg = _serializer.Deserialize(jsonReader); if (msg != null) + { +#if DEBUG_PACKETS + Console.WriteLine($"<- {(GatewayOpCode)msg.Operation} [{msg.Type ?? "none"}] : {(msg.Payload as Newtonsoft.Json.Linq.JToken)?.ToString().Length}"); +#endif + await _receivedGatewayEvent.InvokeAsync((GatewayOpCode)msg.Operation, msg.Sequence, msg.Type, msg.Payload).ConfigureAwait(false); + } } }; WebSocketClient.Closed += async ex => { +#if DEBUG_PACKETS + Console.WriteLine(ex); +#endif + await DisconnectAsync().ConfigureAwait(false); await _disconnectedEvent.InvokeAsync(ex).ConfigureAwait(false); }; @@ -153,6 +169,11 @@ internal override async Task ConnectInternalAsync() var gatewayResponse = await GetGatewayAsync().ConfigureAwait(false); _gatewayUrl = $"{gatewayResponse.Url}?v={DiscordConfig.APIVersion}&encoding={DiscordSocketConfig.GatewayEncoding}&compress=zlib-stream"; } + +#if DEBUG_PACKETS + Console.WriteLine("Connecting to gateway: " + _gatewayUrl); +#endif + await WebSocketClient.ConnectAsync(_gatewayUrl).ConfigureAwait(false); ConnectionState = ConnectionState.Connected; @@ -195,7 +216,7 @@ internal override async Task DisconnectInternalAsync(Exception ex = null) ConnectionState = ConnectionState.Disconnected; } - //Core + #region Core public Task SendGatewayAsync(GatewayOpCode opCode, object payload, RequestOptions options = null) => SendGatewayInternalAsync(opCode, payload, options); private async Task SendGatewayInternalAsync(GatewayOpCode opCode, object payload, RequestOptions options) @@ -213,6 +234,10 @@ private async Task SendGatewayInternalAsync(GatewayOpCode opCode, object payload options.BucketId = GatewayBucket.Get(GatewayBucketType.Unbucketed).Id; await RequestQueue.SendAsync(new WebSocketRequest(WebSocketClient, bytes, true, opCode == GatewayOpCode.Heartbeat, options)).ConfigureAwait(false); await _sentGatewayMessageEvent.InvokeAsync(opCode).ConfigureAwait(false); + +#if DEBUG_PACKETS + Console.WriteLine($"-> {opCode}:\n{SerializeJson(payload)}"); +#endif } public async Task SendIdentifyAsync(int largeThreshold = 100, int shardID = 0, int totalShards = 1, GatewayIntents gatewayIntents = GatewayIntents.AllUnprivileged, (UserStatus, bool, long?, GameModel)? presence = null, RequestOptions options = null) @@ -220,7 +245,9 @@ public async Task SendIdentifyAsync(int largeThreshold = 100, int shardID = 0, i options = RequestOptions.CreateOrClone(options); var props = new Dictionary { - ["$device"] = "Discord.Net" + ["$device"] = "Discord.Net", + ["$os"] = Environment.OSVersion.Platform.ToString(), + [$"browser"] = "Discord.Net" }; var msg = new IdentifyParams() { @@ -237,12 +264,12 @@ public async Task SendIdentifyAsync(int largeThreshold = 100, int shardID = 0, i if (presence.HasValue) { - msg.Presence = new StatusUpdateParams + msg.Presence = new PresenceUpdateParams { Status = presence.Value.Item1, IsAFK = presence.Value.Item2, IdleSince = presence.Value.Item3, - Game = presence.Value.Item4, + Activities = new object[] { presence.Value.Item4 } }; } @@ -264,18 +291,18 @@ public async Task SendHeartbeatAsync(int lastSeq, RequestOptions options = null) options = RequestOptions.CreateOrClone(options); await SendGatewayAsync(GatewayOpCode.Heartbeat, lastSeq, options: options).ConfigureAwait(false); } - public async Task SendStatusUpdateAsync(UserStatus status, bool isAFK, long? since, GameModel game, RequestOptions options = null) + public async Task SendPresenceUpdateAsync(UserStatus status, bool isAFK, long? since, GameModel game, RequestOptions options = null) { options = RequestOptions.CreateOrClone(options); - var args = new StatusUpdateParams + var args = new PresenceUpdateParams { Status = status, IdleSince = since, IsAFK = isAFK, - Game = game + Activities = new object[] { game } }; options.BucketId = GatewayBucket.Get(GatewayBucketType.PresenceUpdate).Id; - await SendGatewayAsync(GatewayOpCode.StatusUpdate, args, options: options).ConfigureAwait(false); + await SendGatewayAsync(GatewayOpCode.PresenceUpdate, args, options: options).ConfigureAwait(false); } public async Task SendRequestMembersAsync(IEnumerable guildIds, RequestOptions options = null) { @@ -299,5 +326,6 @@ public async Task SendGuildSyncAsync(IEnumerable guildIds, RequestOptions options = RequestOptions.CreateOrClone(options); await SendGatewayAsync(GatewayOpCode.GuildSync, guildIds, options: options).ConfigureAwait(false); } + #endregion } } diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs index 0418727bf..ab13d93db 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs @@ -6,7 +6,7 @@ namespace Discord.WebSocket { public partial class DiscordSocketClient { - //General + #region General /// Fired when connected to the Discord gateway. public event Func Connected { @@ -45,5 +45,6 @@ public event Func LatencyUpdated internal DiscordSocketClient(DiscordSocketConfig config, DiscordRestApiClient client) : base(config, client) { } + #endregion } } diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs index 2cdff662c..03c85ffc7 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs @@ -24,8 +24,9 @@ namespace Discord.WebSocket /// public partial class DiscordSocketClient : BaseSocketClient, IDiscordClient { + #region DiscordSocketClient private readonly ConcurrentQueue _largeGuilds; - private readonly JsonSerializer _serializer; + internal readonly JsonSerializer _serializer; private readonly DiscordShardedClient _shardedClient; private readonly DiscordSocketClient _parentClient; private readonly ConcurrentQueue _heartbeatTimes; @@ -44,12 +45,13 @@ public partial class DiscordSocketClient : BaseSocketClient, IDiscordClient private RestApplication _applicationInfo; private bool _isDisposed; private GatewayIntents _gatewayIntents; + private ImmutableArray> _defaultStickers; /// /// Provides access to a REST-only client with a shared state from this client. /// public override DiscordSocketRestClient Rest { get; } - /// Gets the shard of of this client. + /// Gets the shard of this client. public int ShardId { get; } /// Gets the current connection state of this client. public ConnectionState ConnectionState => _connection.State; @@ -61,8 +63,9 @@ public partial class DiscordSocketClient : BaseSocketClient, IDiscordClient /// public override IActivity Activity { get => _activity.GetValueOrDefault(); protected set => _activity = Optional.Create(value); } private Optional _activity; + #endregion - //From DiscordSocketConfig + // From DiscordSocketConfig internal int TotalShards { get; private set; } internal int MessageCacheSize { get; private set; } internal int LargeThreshold { get; private set; } @@ -71,10 +74,22 @@ public partial class DiscordSocketClient : BaseSocketClient, IDiscordClient internal WebSocketProvider WebSocketProvider { get; private set; } internal bool AlwaysDownloadUsers { get; private set; } internal int? HandlerTimeout { get; private set; } - - internal new DiscordSocketApiClient ApiClient => base.ApiClient as DiscordSocketApiClient; + internal bool AlwaysDownloadDefaultStickers { get; private set; } + internal bool AlwaysResolveStickers { get; private set; } + internal new DiscordSocketApiClient ApiClient => base.ApiClient; /// public override IReadOnlyCollection Guilds => State.Guilds; + /// + public override IReadOnlyCollection> DefaultStickerPacks + { + get + { + if (_shardedClient != null) + return _shardedClient.DefaultStickerPacks; + else + return _defaultStickers.ToReadOnlyCollection(); + } + } /// public override IReadOnlyCollection PrivateChannels => State.PrivateChannels; /// @@ -130,11 +145,14 @@ private DiscordSocketClient(DiscordSocketConfig config, API.DiscordSocketApiClie UdpSocketProvider = config.UdpSocketProvider; WebSocketProvider = config.WebSocketProvider; AlwaysDownloadUsers = config.AlwaysDownloadUsers; + AlwaysDownloadDefaultStickers = config.AlwaysDownloadDefaultStickers; + AlwaysResolveStickers = config.AlwaysResolveStickers; HandlerTimeout = config.HandlerTimeout; State = new ClientState(0, 0); Rest = new DiscordSocketRestClient(config, ApiClient); _heartbeatTimes = new ConcurrentQueue(); _gatewayIntents = config.GatewayIntents; + _defaultStickers = ImmutableArray.Create>(); _stateLock = new SemaphoreSlim(1, 1); _gatewayLogger = LogManager.CreateLogger(ShardId == 0 && TotalShards == 1 ? "Gateway" : $"Shard #{ShardId}"); @@ -193,6 +211,35 @@ internal override void Dispose(bool disposing) base.Dispose(disposing); } + internal override async Task OnLoginAsync(TokenType tokenType, string token) + { + if (_shardedClient == null && _defaultStickers.Length == 0 && AlwaysDownloadDefaultStickers) + { + var models = await ApiClient.ListNitroStickerPacksAsync().ConfigureAwait(false); + + var builder = ImmutableArray.CreateBuilder>(); + + foreach (var model in models.StickerPacks) + { + var stickers = model.Stickers.Select(x => SocketSticker.Create(this, x)); + + var pack = new StickerPack( + model.Name, + model.Id, + model.SkuId, + model.CoverStickerId.ToNullable(), + model.Description, + model.BannerAssetId, + stickers + ); + + builder.Add(pack); + } + + _defaultStickers = builder.ToImmutable(); + } + } + /// internal override async Task OnLogoutAsync() { @@ -279,7 +326,7 @@ private async Task OnDisconnectingAsync(Exception ex) /// public override async Task GetApplicationInfoAsync(RequestOptions options = null) - => _applicationInfo ?? (_applicationInfo = await ClientHelper.GetApplicationInfoAsync(this, options ?? RequestOptions.Default).ConfigureAwait(false)); + => _applicationInfo ??= await ClientHelper.GetApplicationInfoAsync(this, options ?? RequestOptions.Default).ConfigureAwait(false); /// public override SocketGuild GetGuild(ulong id) @@ -341,6 +388,83 @@ public override SocketUser GetUser(ulong id) /// public override SocketUser GetUser(string username, string discriminator) => State.Users.FirstOrDefault(x => x.Discriminator == discriminator && x.Username == username); + + /// + /// Gets a global application command. + /// + /// The id of the command. + /// The options to be used when sending the request. + /// + /// A ValueTask that represents the asynchronous get operation. The task result contains the application command if found, otherwise + /// . + /// + public async ValueTask GetGlobalApplicationCommandAsync(ulong id, RequestOptions options = null) + { + var command = State.GetCommand(id); + + if (command != null) + return command; + + var model = await ApiClient.GetGlobalApplicationCommandAsync(id, options); + + if (model == null) + return null; + + command = SocketApplicationCommand.Create(this, model); + + State.AddCommand(command); + + return command; + } + /// + /// Gets a collection of all global commands. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection of global + /// application commands. + /// + public async Task> GetGlobalApplicationCommandsAsync(RequestOptions options = null) + { + var commands = (await ApiClient.GetGlobalApplicationCommandsAsync(options)).Select(x => SocketApplicationCommand.Create(this, x)); + + foreach(var command in commands) + { + State.AddCommand(command); + } + + return commands.ToImmutableArray(); + } + + public async Task CreateGlobalApplicationCommandAsync(ApplicationCommandProperties properties, RequestOptions options = null) + { + var model = await InteractionHelper.CreateGlobalCommandAsync(this, properties, options).ConfigureAwait(false); + + var entity = State.GetOrAddCommand(model.Id, (id) => SocketApplicationCommand.Create(this, model)); + + //Update it in case it was cached + entity.Update(model); + + return entity; + } + public async Task> BulkOverwriteGlobalApplicationCommandsAsync( + ApplicationCommandProperties[] properties, RequestOptions options = null) + { + var models = await InteractionHelper.BulkOverwriteGlobalCommandsAsync(this, properties, options); + + var entities = models.Select(x => SocketApplicationCommand.Create(this, x)); + + //Purge our previous commands + State.PurgeCommands(x => x.IsGlobalCommand); + + foreach(var entity in entities) + { + State.AddCommand(entity); + } + + return entities.ToImmutableArray(); + } + /// /// Clears cached users from the client. /// @@ -366,6 +490,56 @@ internal SocketGlobalUser GetOrCreateSelfUser(ClientState state, Discord.API.Use internal void RemoveUser(ulong id) => State.RemoveUser(id); + /// + public override async Task GetStickerAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) + { + var sticker = _defaultStickers.FirstOrDefault(x => x.Stickers.Any(y => y.Id == id))?.Stickers.FirstOrDefault(x => x.Id == id); + + if (sticker != null) + return sticker; + + foreach(var guild in Guilds) + { + sticker = await guild.GetStickerAsync(id, CacheMode.CacheOnly).ConfigureAwait(false); + + if (sticker != null) + return sticker; + } + + if (mode == CacheMode.CacheOnly) + return null; + + var model = await ApiClient.GetStickerAsync(id, options).ConfigureAwait(false); + + if(model == null) + return null; + + + if (model.GuildId.IsSpecified) + { + var guild = State.GetGuild(model.GuildId.Value); + + //Since the sticker can be from another guild, check if we are in the guild or its in the cache + if (guild != null) + sticker = guild.AddOrUpdateSticker(model); + else + sticker = SocketSticker.Create(this, model); + return sticker; + } + else + { + return SocketSticker.Create(this, model); + } + } + + /// + /// Gets a sticker. + /// + /// The unique identifier of the sticker. + /// A sticker if found, otherwise . + public SocketSticker GetSticker(ulong id) + => GetStickerAsync(id, CacheMode.CacheOnly).GetAwaiter().GetResult(); + /// public override async ValueTask> GetVoiceRegionsAsync(RequestOptions options = null) { @@ -402,6 +576,8 @@ public override async Task DownloadUsersAsync(IEnumerable guilds) { if (ConnectionState == ConnectionState.Connected) { + EnsureGatewayIntent(GatewayIntents.GuildMembers); + //Race condition leads to guilds being requested twice, probably okay await ProcessUserDownloadsAsync(guilds.Select(x => GetGuild(x.Id)).Where(x => x != null)).ConfigureAwait(false); } @@ -493,7 +669,7 @@ private async Task SendStatusAsync() var presence = BuildCurrentStatus() ?? (UserStatus.Online, false, null, null); - await ApiClient.SendStatusUpdateAsync( + await ApiClient.SendPresenceUpdateAsync( status: presence.Item1, isAFK: presence.Item2, since: presence.Item3, @@ -510,7 +686,7 @@ await ApiClient.SendStatusUpdateAsync( return null; GameModel game = null; - // Discord only accepts rich presence over RPC, don't even bother building a payload + //Discord only accepts rich presence over RPC, don't even bother building a payload if (activity.GetValueOrDefault() != null) { @@ -532,6 +708,7 @@ await ApiClient.SendStatusUpdateAsync( game); } + #region ProcessMessageAsync private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string type, object payload) { if (seq != null) @@ -604,7 +781,7 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty case GatewayOpCode.Dispatch: switch (type) { - //Connection + #region Connection case "READY": { try @@ -615,6 +792,7 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty var state = new ClientState(data.Guilds.Length, data.PrivateChannels.Length); var currentUser = SocketSelfUser.Create(this, state, data.User); + Rest.CreateRestSelfUser(data.User); var activities = _activity.IsSpecified ? ImmutableList.Create(_activity.Value) : null; currentUser.Presence = new SocketPresence(Status, null, activities); ApiClient.CurrentUserId = currentUser.Id; @@ -680,8 +858,9 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty await _gatewayLogger.InfoAsync("Resumed previous session").ConfigureAwait(false); } break; + #endregion - //Guilds + #region Guilds case "GUILD_CREATE": { var data = (payload as JToken).ToObject(_serializer); @@ -831,8 +1010,62 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty } } break; + case "GUILD_STICKERS_UPDATE": + { + await _gatewayLogger.DebugAsync($"Received Dispatch (GUILD_STICKERS_UPDATE)").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + var guild = State.GetGuild(data.GuildId); - //Channels + if (guild == null) + { + await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false); + return; + } + + var newStickers = data.Stickers.Where(x => !guild.Stickers.Any(y => y.Id == x.Id)); + var deletedStickers = guild.Stickers.Where(x => !data.Stickers.Any(y => y.Id == x.Id)); + var updatedStickers = data.Stickers.Select(x => + { + var s = guild.Stickers.FirstOrDefault(y => y.Id == x.Id); + if (s == null) + return null; + + var e = s.Equals(x); + if (!e) + { + return (s, x) as (SocketCustomSticker Entity, API.Sticker Model)?; + } + else + { + return null; + } + }).Where(x => x.HasValue).Select(x => x.Value).ToArray(); + + foreach (var model in newStickers) + { + var entity = guild.AddSticker(model); + await TimedInvokeAsync(_guildStickerCreated, nameof(GuildStickerCreated), entity); + } + foreach (var sticker in deletedStickers) + { + var entity = guild.RemoveSticker(sticker.Id); + await TimedInvokeAsync(_guildStickerDeleted, nameof(GuildStickerDeleted), entity); + } + foreach (var entityModelPair in updatedStickers) + { + var before = entityModelPair.Entity.Clone(); + + entityModelPair.Entity.Update(entityModelPair.Model); + + await TimedInvokeAsync(_guildStickerUpdated, nameof(GuildStickerUpdated), before, entityModelPair.Entity); + } + } + break; + #endregion + + #region Channels case "CHANNEL_CREATE": { await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false); @@ -934,8 +1167,9 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty } } break; + #endregion - //Members + #region Members case "GUILD_MEMBER_ADD": { await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_MEMBER_ADD)").ConfigureAwait(false); @@ -1066,6 +1300,32 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty } } break; + case "GUILD_JOIN_REQUEST_DELETE": + { + await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_JOIN_REQUEST_DELETE)").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + var guild = State.GetGuild(data.GuildId); + + if (guild == null) + { + await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false); + return; + } + + var user = guild.RemoveUser(data.UserId); + guild.MemberCount--; + + var cacheableUser = new Cacheable(user, data.UserId, user != null, () => Task.FromResult((SocketGuildUser)null)); + + await TimedInvokeAsync(_guildJoinRequestDeletedEvent, nameof(GuildJoinRequestDeleted), cacheableUser, guild).ConfigureAwait(false); + } + break; + #endregion + + #region DM Channels + case "CHANNEL_RECIPIENT_ADD": { await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_RECIPIENT_ADD)").ConfigureAwait(false); @@ -1107,7 +1367,9 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty } break; - //Roles + #endregion + + #region Roles case "GUILD_ROLE_CREATE": { await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_ROLE_CREATE)").ConfigureAwait(false); @@ -1199,8 +1461,9 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty } } break; + #endregion - //Bans + #region Bans case "GUILD_BAN_ADD": { await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_BAN_ADD)").ConfigureAwait(false); @@ -1253,8 +1516,9 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty } } break; + #endregion - //Messages + #region Messages case "MESSAGE_CREATE": { await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false); @@ -1344,7 +1608,7 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty } else { - //Edited message isnt in cache, create a detached one + //Edited message isn't in cache, create a detached one SocketUser author; if (data.Author.IsSpecified) { @@ -1585,8 +1849,9 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty await TimedInvokeAsync(_messagesBulkDeletedEvent, nameof(MessagesBulkDeleted), cacheableList, cacheableChannel).ConfigureAwait(false); } break; + #endregion - //Statuses + #region Statuses case "PRESENCE_UPDATE": { await _gatewayLogger.DebugAsync("Received Dispatch (PRESENCE_UPDATE)").ConfigureAwait(false); @@ -1674,8 +1939,9 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty await TimedInvokeAsync(_userIsTypingEvent, nameof(UserIsTyping), cacheableUser, cacheableChannel).ConfigureAwait(false); } break; + #endregion - //Users + #region Users case "USER_UPDATE": { await _gatewayLogger.DebugAsync("Received Dispatch (USER_UPDATE)").ConfigureAwait(false); @@ -1694,8 +1960,9 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty } } break; + #endregion - //Voice + #region Voice case "VOICE_STATE_UPDATE": { await _gatewayLogger.DebugAsync("Received Dispatch (VOICE_STATE_UPDATE)").ConfigureAwait(false); @@ -1732,7 +1999,7 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty after = SocketVoiceState.Create(null, data); } - // per g250k, this should always be sent, but apparently not always + //Per g250k, this should always be sent, but apparently not always user = guild.GetUser(data.UserId) ?? (data.Member.IsSpecified ? guild.AddOrUpdateUser(data.Member.Value) : null); if (user == null) @@ -1767,6 +2034,29 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty } } + if (user is SocketGuildUser guildUser && data.ChannelId.HasValue) + { + SocketStageChannel stage = guildUser.Guild.GetStageChannel(data.ChannelId.Value); + + if (stage != null && before.VoiceChannel != null && after.VoiceChannel != null) + { + if (!before.RequestToSpeakTimestamp.HasValue && after.RequestToSpeakTimestamp.HasValue) + { + await TimedInvokeAsync(_requestToSpeak, nameof(RequestToSpeak), stage, guildUser); + return; + } + if(before.IsSuppressed && !after.IsSuppressed) + { + await TimedInvokeAsync(_speakerAdded, nameof(SpeakerAdded), stage, guildUser); + return; + } + if(!before.IsSuppressed && after.IsSuppressed) + { + await TimedInvokeAsync(_speakerRemoved, nameof(SpeakerRemoved), stage, guildUser); + } + } + } + await TimedInvokeAsync(_userVoiceStateUpdatedEvent, nameof(UserVoiceStateUpdated), user, before, after).ConfigureAwait(false); } break; @@ -1801,8 +2091,9 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty } break; + #endregion - //Invites + #region Invites case "INVITE_CREATE": { await _gatewayLogger.DebugAsync("Received Dispatch (INVITE_CREATE)").ConfigureAwait(false); @@ -1859,8 +2150,529 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty } } break; + #endregion + + #region Interactions + case "INTERACTION_CREATE": + { + await _gatewayLogger.DebugAsync("Received Dispatch (INTERACTION_CREATE)").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + SocketChannel channel = null; + if(data.ChannelId.IsSpecified) + { + channel = State.GetChannel(data.ChannelId.Value); + } + else if (data.User.IsSpecified) + { + channel = State.GetDMChannel(data.User.Value.Id); + } + + if (channel == null) + { + var channelModel = await Rest.ApiClient.GetChannelAsync(data.ChannelId.Value); + + if (data.GuildId.IsSpecified) + channel = SocketTextChannel.Create(State.GetGuild(data.GuildId.Value), State, channelModel); + else + channel = (SocketChannel)SocketChannel.CreatePrivate(this, State, channelModel); + + State.AddChannel(channel); + } + + if (channel is ISocketMessageChannel textChannel) + { + var guild = (channel as SocketGuildChannel)?.Guild; + if (guild != null && !guild.IsSynced) + { + await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false); + return; + } + + var interaction = SocketInteraction.Create(this, data, channel as ISocketMessageChannel); + + await TimedInvokeAsync(_interactionCreatedEvent, nameof(InteractionCreated), interaction).ConfigureAwait(false); + + switch (interaction) + { + case SocketSlashCommand slashCommand: + await TimedInvokeAsync(_slashCommandExecuted, nameof(SlashCommandExecuted), slashCommand).ConfigureAwait(false); + break; + case SocketMessageComponent messageComponent: + if(messageComponent.Data.Type == ComponentType.SelectMenu) + await TimedInvokeAsync(_selectMenuExecuted, nameof(SelectMenuExecuted), messageComponent).ConfigureAwait(false); + if(messageComponent.Data.Type == ComponentType.Button) + await TimedInvokeAsync(_buttonExecuted, nameof(ButtonExecuted), messageComponent).ConfigureAwait(false); + break; + case SocketUserCommand userCommand: + await TimedInvokeAsync(_userCommandExecuted, nameof(UserCommandExecuted), userCommand).ConfigureAwait(false); + break; + case SocketMessageCommand messageCommand: + await TimedInvokeAsync(_messageCommandExecuted, nameof(MessageCommandExecuted), messageCommand).ConfigureAwait(false); + break; + case SocketAutocompleteInteraction autocomplete: + await TimedInvokeAsync(_autocompleteExecuted, nameof(AutocompleteExecuted), autocomplete).ConfigureAwait(false); + break; + } + } + else + { + await UnknownChannelAsync(type, data.ChannelId.Value).ConfigureAwait(false); + return; + } + } + break; + case "APPLICATION_COMMAND_CREATE": + { + await _gatewayLogger.DebugAsync("Received Dispatch (APPLICATION_COMMAND_CREATE)").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + if (data.GuildId.IsSpecified) + { + var guild = State.GetGuild(data.GuildId.Value); + if (guild == null) + { + await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false); + return; + } + } + + var applicationCommand = SocketApplicationCommand.Create(this, data); + + State.AddCommand(applicationCommand); + + await TimedInvokeAsync(_applicationCommandCreated, nameof(ApplicationCommandCreated), applicationCommand).ConfigureAwait(false); + } + break; + case "APPLICATION_COMMAND_UPDATE": + { + await _gatewayLogger.DebugAsync("Received Dispatch (APPLICATION_COMMAND_UPDATE)").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + if (data.GuildId.IsSpecified) + { + var guild = State.GetGuild(data.GuildId.Value); + if (guild == null) + { + await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false); + return; + } + } + + var applicationCommand = SocketApplicationCommand.Create(this, data); + + State.AddCommand(applicationCommand); + + await TimedInvokeAsync(_applicationCommandUpdated, nameof(ApplicationCommandUpdated), applicationCommand).ConfigureAwait(false); + } + break; + case "APPLICATION_COMMAND_DELETE": + { + await _gatewayLogger.DebugAsync("Received Dispatch (APPLICATION_COMMAND_DELETE)").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + if (data.GuildId.IsSpecified) + { + var guild = State.GetGuild(data.GuildId.Value); + if (guild == null) + { + await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false); + return; + } + } + + var applicationCommand = SocketApplicationCommand.Create(this, data); + + State.RemoveCommand(applicationCommand.Id); + + await TimedInvokeAsync(_applicationCommandDeleted, nameof(ApplicationCommandDeleted), applicationCommand).ConfigureAwait(false); + } + break; + #endregion + + #region Threads + case "THREAD_CREATE": + { + await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_CREATE)").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + var guild = State.GetGuild(data.GuildId.Value); + + if (guild == null) + { + await UnknownGuildAsync(type, data.GuildId.Value); + return; + } + + SocketThreadChannel threadChannel = null; - //Ignored (User only) + if ((threadChannel = guild.ThreadChannels.FirstOrDefault(x => x.Id == data.Id)) != null) + { + threadChannel.Update(State, data); + + if(data.ThreadMember.IsSpecified) + threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser); + } + else + { + threadChannel = (SocketThreadChannel)guild.AddChannel(State, data); + if (data.ThreadMember.IsSpecified) + threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser); + } + + await TimedInvokeAsync(_threadCreated, nameof(ThreadCreated), threadChannel).ConfigureAwait(false); + } + + break; + case "THREAD_UPDATE": + { + await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_UPDATE)").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + var guild = State.GetGuild(data.GuildId.Value); + if (guild == null) + { + await UnknownGuildAsync(type, data.GuildId.Value); + return; + } + + var threadChannel = guild.ThreadChannels.FirstOrDefault(x => x.Id == data.Id); + var before = threadChannel != null + ? new Cacheable(threadChannel.Clone(), data.Id, true, () => Task.FromResult((SocketThreadChannel)null)) + : new Cacheable(null, data.Id, false, () => Task.FromResult((SocketThreadChannel)null)); + + if (threadChannel != null) + { + threadChannel.Update(State, data); + + if (data.ThreadMember.IsSpecified) + threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser); + } + else + { + //Thread is updated but was not cached, likely meaning the thread was unarchived. + threadChannel = (SocketThreadChannel)guild.AddChannel(State, data); + if (data.ThreadMember.IsSpecified) + threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser); + } + + if (!(guild?.IsSynced ?? true)) + { + await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false); + return; + } + + await TimedInvokeAsync(_threadUpdated, nameof(ThreadUpdated), before, threadChannel).ConfigureAwait(false); + } + break; + case "THREAD_DELETE": + { + await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_DELETE)").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + var guild = State.GetGuild(data.GuildId.Value); + + if(guild == null) + { + await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false); + return; + } + + var thread = (SocketThreadChannel)guild.GetChannel(data.Id); + + var cacheable = new Cacheable(thread, data.Id, thread != null, null); + + await TimedInvokeAsync(_threadDeleted, nameof(ThreadDeleted), cacheable).ConfigureAwait(false); + } + break; + case "THREAD_LIST_SYNC": + { + await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_LIST_SYNC)").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + var guild = State.GetGuild(data.GuildId); + + if(guild == null) + { + await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false); + return; + } + + foreach(var thread in data.Threads) + { + var entity = guild.ThreadChannels.FirstOrDefault(x => x.Id == thread.Id); + + if(entity == null) + { + entity = (SocketThreadChannel)guild.AddChannel(State, thread); + } + else + { + entity.Update(State, thread); + } + + foreach(var member in data.Members.Where(x => x.Id.Value == entity.Id)) + { + var guildMember = guild.GetUser(member.Id.Value); + + entity.AddOrUpdateThreadMember(member, guildMember); + } + } + } + break; + case "THREAD_MEMBER_UPDATE": + { + await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_MEMBER_UPDATE)").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + var thread = (SocketThreadChannel)State.GetChannel(data.Id.Value); + + if (thread == null) + { + await UnknownChannelAsync(type, data.Id.Value); + return; + } + + thread.AddOrUpdateThreadMember(data, thread.Guild.CurrentUser); + } + + break; + case "THREAD_MEMBERS_UPDATE": + { + await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_MEMBERS_UPDATE)").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + var guild = State.GetGuild(data.GuildId); + + if (guild == null) + { + await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false); + return; + } + + var thread = (SocketThreadChannel)guild.GetChannel(data.Id); + + if(thread == null) + { + await UnknownChannelAsync(type, data.Id); + return; + } + + IReadOnlyCollection leftUsers = null; + IReadOnlyCollection joinUsers = null; + + + if (data.RemovedMemberIds.IsSpecified) + { + leftUsers = thread.RemoveUsers(data.RemovedMemberIds.Value); + } + + if (data.AddedMembers.IsSpecified) + { + List newThreadMembers = new List(); + foreach(var threadMember in data.AddedMembers.Value) + { + SocketGuildUser guildMember; + + if (threadMember.Member.IsSpecified) + { + guildMember = guild.AddOrUpdateUser(threadMember.Member.Value); + } + else + { + guildMember = guild.GetUser(threadMember.UserId.Value); + } + + newThreadMembers.Add(thread.AddOrUpdateThreadMember(threadMember, guildMember)); + } + + if (newThreadMembers.Any()) + joinUsers = newThreadMembers.ToImmutableArray(); + } + + if (leftUsers != null) + { + foreach(var threadUser in leftUsers) + { + await TimedInvokeAsync(_threadMemberLeft, nameof(ThreadMemberLeft), threadUser).ConfigureAwait(false); + } + } + + if(joinUsers != null) + { + foreach(var threadUser in joinUsers) + { + await TimedInvokeAsync(_threadMemberJoined, nameof(ThreadMemberJoined), threadUser).ConfigureAwait(false); + } + } + } + + break; + #endregion + + #region Stage Channels + case "STAGE_INSTANCE_CREATE" or "STAGE_INSTANCE_UPDATE" or "STAGE_INSTANCE_DELETE": + { + await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + var guild = State.GetGuild(data.GuildId); + + if(guild == null) + { + await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false); + return; + } + + var stageChannel = guild.GetStageChannel(data.ChannelId); + + if(stageChannel == null) + { + await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false); + return; + } + + SocketStageChannel before = type == "STAGE_INSTANCE_UPDATE" ? stageChannel.Clone() : null; + + stageChannel.Update(data, type == "STAGE_INSTANCE_CREATE"); + + switch (type) + { + case "STAGE_INSTANCE_CREATE": + await TimedInvokeAsync(_stageStarted, nameof(StageStarted), stageChannel).ConfigureAwait(false); + return; + case "STAGE_INSTANCE_DELETE": + await TimedInvokeAsync(_stageEnded, nameof(StageEnded), stageChannel).ConfigureAwait(false); + return; + case "STAGE_INSTANCE_UPDATE": + await TimedInvokeAsync(_stageUpdated, nameof(StageUpdated), before, stageChannel).ConfigureAwait(false); + return; + } + } + break; + #endregion + + #region Guild Scheduled Events + case "GUILD_SCHEDULED_EVENT_CREATE": + { + await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + var guild = State.GetGuild(data.GuildId); + + if (guild == null) + { + await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false); + return; + } + + var newEvent = guild.AddOrUpdateEvent(data); + + await TimedInvokeAsync(_guildScheduledEventCancelled, nameof(GuildScheduledEventCreated), newEvent).ConfigureAwait(false); + } + break; + case "GUILD_SCHEDULED_EVENT_UPDATE": + { + await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + var guild = State.GetGuild(data.GuildId); + + if (guild == null) + { + await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false); + return; + } + + var before = guild.GetEvent(data.Id); + + var beforeCacheable = new Cacheable(before, data.Id, before != null, () => Task.FromResult((SocketGuildEvent)null)); + + var after = guild.AddOrUpdateEvent(data); + + if((before != null ? before.Status != GuildScheduledEventStatus.Completed : true) && data.Status == GuildScheduledEventStatus.Completed) + { + await TimedInvokeAsync(_guildScheduledEventCompleted, nameof(GuildScheduledEventCompleted), after).ConfigureAwait(false); + } + else if((before != null ? before.Status != GuildScheduledEventStatus.Active : false) && data.Status == GuildScheduledEventStatus.Active) + { + await TimedInvokeAsync(_guildScheduledEventStarted, nameof(GuildScheduledEventStarted), after).ConfigureAwait(false); + } + else await TimedInvokeAsync(_guildScheduledEventUpdated, nameof(GuildScheduledEventUpdated), beforeCacheable, after).ConfigureAwait(false); + } + break; + case "GUILD_SCHEDULED_EVENT_DELETE": + { + await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + var guild = State.GetGuild(data.GuildId); + + if (guild == null) + { + await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false); + return; + } + + var guildEvent = guild.RemoveEvent(data.Id) ?? SocketGuildEvent.Create(this, guild, data); + + await TimedInvokeAsync(_guildScheduledEventCancelled, nameof(GuildScheduledEventCancelled), guildEvent).ConfigureAwait(false); + } + break; + case "GUILD_SCHEDULED_EVENT_USER_ADD" or "GUILD_SCHEDULED_EVENT_USER_REMOVE": + { + await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + + var guild = State.GetGuild(data.GuildId); + + if(guild == null) + { + await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false); + return; + } + + var guildEvent = guild.GetEvent(data.EventId); + + if (guildEvent == null) + { + await UnknownGuildEventAsync(type, data.EventId, data.GuildId).ConfigureAwait(false); + return; + } + + var user = (SocketUser)guild.GetUser(data.UserId) ?? State.GetUser(data.UserId); + + var cacheableUser = new Cacheable(user, data.UserId, user != null, () => Rest.GetUserAsync(data.UserId)); + + switch (type) + { + case "GUILD_SCHEDULED_EVENT_USER_ADD": + await TimedInvokeAsync(_guildScheduledEventUserAdd, nameof(GuildScheduledEventUserAdd), cacheableUser, guildEvent).ConfigureAwait(false); + break; + case "GUILD_SCHEDULED_EVENT_USER_REMOVE": + await TimedInvokeAsync(_guildScheduledEventUserRemove, nameof(GuildScheduledEventUserRemove), cacheableUser, guildEvent).ConfigureAwait(false); + break; + } + } + break; + + #endregion + + #region Ignored (User only) case "CHANNEL_PINS_ACK": await _gatewayLogger.DebugAsync("Ignored Dispatch (CHANNEL_PINS_ACK)").ConfigureAwait(false); break; @@ -1882,11 +2694,13 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty case "WEBHOOKS_UPDATE": await _gatewayLogger.DebugAsync("Ignored Dispatch (WEBHOOKS_UPDATE)").ConfigureAwait(false); break; + #endregion - //Others + #region Others default: await _gatewayLogger.WarningAsync($"Unknown Dispatch ({type})").ConfigureAwait(false); break; + #endregion } break; default: @@ -1899,6 +2713,7 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty await _gatewayLogger.ErrorAsync($"Error handling {opCode}{(type != null ? $" ({type})" : "")}", ex).ConfigureAwait(false); } } + #endregion private async Task RunHeartbeatAsync(int intervalMillis, CancellationToken cancelToken) { @@ -2018,6 +2833,18 @@ internal void RemoveDMChannels() channel.Recipient.GlobalUser.RemoveRef(this); } + internal void EnsureGatewayIntent(GatewayIntents intents) + { + if (!_gatewayIntents.HasFlag(intents)) + { + var vals = Enum.GetValues(typeof(GatewayIntents)).Cast(); + + var missingValues = vals.Where(x => intents.HasFlag(x) && !_gatewayIntents.HasFlag(x)); + + throw new InvalidOperationException($"Missing required gateway intent{(missingValues.Count() > 1 ? "s" : "")} {string.Join(", ", missingValues.Select(x => x.ToString()))} in order to execute this operation."); + } + } + private async Task GuildAvailableAsync(SocketGuild guild) { if (!guild.IsConnected) @@ -2158,6 +2985,12 @@ private async Task UnknownGuildAsync(string evnt, ulong guildId) string details = $"{evnt} Guild={guildId}"; await _gatewayLogger.WarningAsync($"Unknown Guild ({details}).").ConfigureAwait(false); } + + private async Task UnknownGuildEventAsync(string evnt, ulong eventId, ulong guildId) + { + string details = $"{evnt} Event={eventId} Guild={guildId}"; + await _gatewayLogger.WarningAsync($"Unknown Guild Event ({details}).").ConfigureAwait(false); + } private async Task UnsyncedGuildAsync(string evnt, ulong guildId) { string details = $"{evnt} Guild={guildId}"; @@ -2166,7 +2999,7 @@ private async Task UnsyncedGuildAsync(string evnt, ulong guildId) internal int GetAudioId() => _nextAudioId++; - //IDiscordClient + #region IDiscordClient /// async Task IDiscordClient.GetApplicationInfoAsync(RequestOptions options) => await GetApplicationInfoAsync().ConfigureAwait(false); @@ -2216,11 +3049,19 @@ async Task> IDiscordClient.GetVoiceRegionsAsyn async Task IDiscordClient.GetVoiceRegionAsync(string id, RequestOptions options) => await GetVoiceRegionAsync(id, options).ConfigureAwait(false); + /// + async Task IDiscordClient.GetGlobalApplicationCommandAsync(ulong id, RequestOptions options) + => await GetGlobalApplicationCommandAsync(id, options); + /// + async Task> IDiscordClient.GetGlobalApplicationCommandsAsync(RequestOptions options) + => await GetGlobalApplicationCommandsAsync(options); + /// async Task IDiscordClient.StartAsync() => await StartAsync().ConfigureAwait(false); /// async Task IDiscordClient.StopAsync() => await StopAsync().ConfigureAwait(false); + #endregion } } diff --git a/src/Discord.Net.WebSocket/DiscordSocketConfig.cs b/src/Discord.Net.WebSocket/DiscordSocketConfig.cs index 22a201c67..8615eac71 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketConfig.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketConfig.cs @@ -49,8 +49,31 @@ public class DiscordSocketConfig : DiscordRestConfig /// /// Gets or sets the total number of shards for this application. /// + /// + /// If this is left in a sharded client the bot will get the recommended shard + /// count from discord and use that. + /// public int? TotalShards { get; set; } = null; + /// + /// Gets or sets whether or not the client should download the default stickers on startup. + /// + /// + /// When this is set to default stickers arn't present and cannot be resolved by the client. + /// This will make all default stickers have the type of . + /// + public bool AlwaysDownloadDefaultStickers { get; set; } = false; + + /// + /// Gets or sets whether or not the client should automatically resolve the stickers sent on a message. + /// + /// + /// Note if a sticker isn't cached the client will preform a rest request to resolve it. This + /// may be very rest heavy depending on your bots size, it isn't recommended to use this with large scale bots as you + /// can get ratelimited easily. + /// + public bool AlwaysResolveStickers { get; set; } = false; + /// /// Gets or sets the number of messages per channel that should be kept in cache. Setting this to zero /// disables the message cache entirely. @@ -79,7 +102,7 @@ public class DiscordSocketConfig : DiscordRestConfig /// /// /// By default, the Discord gateway will only send offline members if a guild has less than a certain number - /// of members (determined by in this library). This behaviour is why + /// of members (determined by in this library). This behavior is why /// sometimes a user may be missing from the WebSocket cache for collections such as /// . /// @@ -137,13 +160,13 @@ public int MaxWaitBetweenGuildAvailablesBeforeReady { get { - return this.maxWaitForGuildAvailable; + return maxWaitForGuildAvailable; } set { - Preconditions.AtLeast(value, 0, nameof(this.MaxWaitBetweenGuildAvailablesBeforeReady)); - this.maxWaitForGuildAvailable = value; + Preconditions.AtLeast(value, 0, nameof(MaxWaitBetweenGuildAvailablesBeforeReady)); + maxWaitForGuildAvailable = value; } } diff --git a/src/Discord.Net.WebSocket/DiscordVoiceApiClient.cs b/src/Discord.Net.WebSocket/DiscordVoiceApiClient.cs index f78145dbe..62d95402a 100644 --- a/src/Discord.Net.WebSocket/DiscordVoiceApiClient.cs +++ b/src/Discord.Net.WebSocket/DiscordVoiceApiClient.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS1591 using Discord.API; using Discord.API.Voice; using Discord.Net.Converters; @@ -18,6 +17,7 @@ namespace Discord.Audio { internal class DiscordVoiceAPIClient : IDisposable { + #region DiscordVoiceAPIClient public const int MaxBitrate = 128 * 1024; public const string Mode = "xsalsa20_poly1305"; @@ -126,8 +126,9 @@ public async Task SendAsync(byte[] data, int offset, int bytes) await _udp.SendAsync(data, offset, bytes).ConfigureAwait(false); await _sentDataEvent.InvokeAsync(bytes).ConfigureAwait(false); } + #endregion - //WebSocket + #region WebSocket public async Task SendHeartbeatAsync(RequestOptions options = null) { await SendAsync(VoiceOpCode.Heartbeat, DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), options: options).ConfigureAwait(false); @@ -208,10 +209,12 @@ public async Task DisconnectAsync() } private async Task DisconnectInternalAsync() { - if (ConnectionState == ConnectionState.Disconnected) return; + if (ConnectionState == ConnectionState.Disconnected) + return; ConnectionState = ConnectionState.Disconnecting; - try { _connectCancelToken?.Cancel(false); } + try + { _connectCancelToken?.Cancel(false); } catch { } //Wait for tasks to complete @@ -220,8 +223,9 @@ private async Task DisconnectInternalAsync() ConnectionState = ConnectionState.Disconnected; } + #endregion - //Udp + #region Udp public async Task SendDiscoveryAsync(uint ssrc) { var packet = new byte[70]; @@ -252,8 +256,9 @@ public void SetUdpEndpoint(string ip, int port) { _udp.SetDestination(ip, port); } + #endregion - //Helpers + #region Helpers private static double ToMilliseconds(Stopwatch stopwatch) => Math.Round((double)stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0, 2); private string SerializeJson(object value) { @@ -269,5 +274,6 @@ private T DeserializeJson(Stream jsonStream) using (JsonReader reader = new JsonTextReader(text)) return _serializer.Deserialize(reader); } + #endregion } } diff --git a/src/Discord.Net.WebSocket/Entities/Channels/ISocketMessageChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/ISocketMessageChannel.cs index b4625f799..1103f8feb 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/ISocketMessageChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/ISocketMessageChannel.cs @@ -34,16 +34,19 @@ public interface ISocketMessageChannel : IMessageChannel /// If null, all mentioned roles and users will be notified. /// /// The message references to be included. Used to reply to specific messages. + /// The message components to be included with this message. Used for interactions. + /// A collection of stickers to send with the message. + /// A array of s to send with this response. Max 10. /// /// A task that represents an asynchronous send operation for delivering the message. The task result /// contains the sent message. /// - new Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null); + new Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null); /// /// Sends a file to this message channel with an optional caption. /// /// - /// This method follows the same behavior as described in . + /// This method follows the same behavior as described in . /// Please visit its documentation for more details on this method. /// /// The file path of the file. @@ -57,16 +60,19 @@ public interface ISocketMessageChannel : IMessageChannel /// If null, all mentioned roles and users will be notified. /// /// The message references to be included. Used to reply to specific messages. + /// The message components to be included with this message. Used for interactions. + /// A collection of stickers to send with the file. + /// A array of s to send with this response. Max 10. /// /// A task that represents an asynchronous send operation for delivering the message. The task result /// contains the sent message. /// - new Task SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null); + new Task SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null); /// /// Sends a file to this message channel with an optional caption. /// /// - /// This method follows the same behavior as described in . + /// This method follows the same behavior as described in . /// Please visit its documentation for more details on this method. /// /// The of the file to be sent. @@ -81,11 +87,14 @@ public interface ISocketMessageChannel : IMessageChannel /// If null, all mentioned roles and users will be notified. /// /// The message references to be included. Used to reply to specific messages. + /// The message components to be included with this message. Used for interactions. + /// A collection of stickers to send with the file. + /// A array of s to send with this response. Max 10. /// /// A task that represents an asynchronous send operation for delivering the message. The task result /// contains the sent message. /// - new Task SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null); + new Task SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null); /// /// Gets a cached message from this channel. diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs index b90c1976a..9c7dd4fbd 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketCategoryChannel.cs @@ -14,6 +14,7 @@ namespace Discord.WebSocket [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketCategoryChannel : SocketGuildChannel, ICategoryChannel { + #region SocketCategoryChannel /// public override IReadOnlyCollection Users => Guild.Users.Where(x => Permissions.GetValue( @@ -41,8 +42,9 @@ internal SocketCategoryChannel(DiscordSocketClient discord, ulong id, SocketGuil entity.Update(state, model); return entity; } + #endregion - //Users + #region Users /// public override SocketGuildUser GetUser(ulong id) { @@ -59,21 +61,24 @@ public override SocketGuildUser GetUser(ulong id) private string DebuggerDisplay => $"{Name} ({Id}, Category)"; internal new SocketCategoryChannel Clone() => MemberwiseClone() as SocketCategoryChannel; + #endregion - // IGuildChannel + #region IGuildChannel /// IAsyncEnumerable> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => ImmutableArray.Create>(Users).ToAsyncEnumerable(); /// Task IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) => Task.FromResult(GetUser(id)); + #endregion - //IChannel + #region IChannel /// IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => ImmutableArray.Create>(Users).ToAsyncEnumerable(); /// Task IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) => Task.FromResult(GetUser(id)); + #endregion } } diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketChannel.cs index 13c0c9b4f..758ee9271 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketChannel.cs @@ -13,6 +13,7 @@ namespace Discord.WebSocket [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public abstract class SocketChannel : SocketEntity, IChannel { + #region SocketChannel /// /// Gets when the channel is created. /// @@ -30,19 +31,17 @@ internal SocketChannel(DiscordSocketClient discord, ulong id) /// Unexpected channel type is created. internal static ISocketPrivateChannel CreatePrivate(DiscordSocketClient discord, ClientState state, Model model) { - switch (model.Type) + return model.Type switch { - case ChannelType.DM: - return SocketDMChannel.Create(discord, state, model); - case ChannelType.Group: - return SocketGroupChannel.Create(discord, state, model); - default: - throw new InvalidOperationException($"Unexpected channel type: {model.Type}"); - } + ChannelType.DM => SocketDMChannel.Create(discord, state, model), + ChannelType.Group => SocketGroupChannel.Create(discord, state, model), + _ => throw new InvalidOperationException($"Unexpected channel type: {model.Type}"), + }; } internal abstract void Update(ClientState state, Model model); + #endregion - //User + #region User /// /// Gets a generic user from this channel. /// @@ -56,8 +55,9 @@ internal static ISocketPrivateChannel CreatePrivate(DiscordSocketClient discord, private string DebuggerDisplay => $"Unknown ({Id}, Channel)"; internal SocketChannel Clone() => MemberwiseClone() as SocketChannel; + #endregion - //IChannel + #region IChannel /// string IChannel.Name => null; @@ -67,5 +67,6 @@ Task IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions optio /// IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => AsyncEnumerable.Empty>(); //Overridden + #endregion } } diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketChannelHelper.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketChannelHelper.cs index 5cfbcc1a8..ccbf9b2b6 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketChannelHelper.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketChannelHelper.cs @@ -70,6 +70,7 @@ public static void AddMessage(ISocketMessageChannel channel, DiscordSocketClient { case SocketDMChannel dmChannel: dmChannel.AddMessage(msg); break; case SocketGroupChannel groupChannel: groupChannel.AddMessage(msg); break; + case SocketThreadChannel threadChannel: threadChannel.AddMessage(msg); break; case SocketTextChannel textChannel: textChannel.AddMessage(msg); break; default: throw new NotSupportedException($"Unexpected {nameof(ISocketMessageChannel)} type."); } @@ -78,13 +79,13 @@ public static void AddMessage(ISocketMessageChannel channel, DiscordSocketClient public static SocketMessage RemoveMessage(ISocketMessageChannel channel, DiscordSocketClient discord, ulong id) { - switch (channel) + return channel switch { - case SocketDMChannel dmChannel: return dmChannel.RemoveMessage(id); - case SocketGroupChannel groupChannel: return groupChannel.RemoveMessage(id); - case SocketTextChannel textChannel: return textChannel.RemoveMessage(id); - default: throw new NotSupportedException($"Unexpected {nameof(ISocketMessageChannel)} type."); - } + SocketDMChannel dmChannel => dmChannel.RemoveMessage(id), + SocketGroupChannel groupChannel => groupChannel.RemoveMessage(id), + SocketTextChannel textChannel => textChannel.RemoveMessage(id), + _ => throw new NotSupportedException($"Unexpected {nameof(ISocketMessageChannel)} type."), + }; } } } diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs index 459707dc7..ea00c9e03 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs @@ -16,6 +16,7 @@ namespace Discord.WebSocket [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketDMChannel : SocketChannel, IDMChannel, ISocketPrivateChannel, ISocketMessageChannel { + #region SocketDMChannel /// /// Gets the recipient of the channel. /// @@ -58,8 +59,9 @@ internal void Update(ClientState state, API.User recipient) /// public Task CloseAsync(RequestOptions options = null) => ChannelHelper.DeleteAsync(this, Discord, options); + #endregion - //Messages + #region Messages /// public SocketMessage GetCachedMessage(ulong id) => null; @@ -137,16 +139,25 @@ public Task> GetPinnedMessagesAsync(RequestOpti /// /// Message content is too long, length must be less or equal to . - public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, allowedMentions, messageReference, options); + public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); /// - public Task SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, allowedMentions, messageReference, options, isSpoiler); + public Task SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, isSpoiler, embeds); /// /// Message content is too long, length must be less or equal to . - public Task SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, allowedMentions, messageReference, options, isSpoiler); + public Task SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, isSpoiler, embeds); + /// + /// Message content is too long, length must be less or equal to . + public Task SendFileAsync(FileAttachment attachment, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, attachment, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); + /// + /// Message content is too long, length must be less or equal to . + public Task SendFilesAsync(IEnumerable attachments, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFilesAsync(this, Discord, attachments, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); + /// public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null) => ChannelHelper.DeleteMessageAsync(this, messageId, Discord, options); @@ -172,8 +183,9 @@ internal SocketMessage RemoveMessage(ulong id) { return null; } + #endregion - //Users + #region Users /// /// Gets a user in this channel from the provided . /// @@ -197,26 +209,31 @@ internal SocketMessage RemoveMessage(ulong id) public override string ToString() => $"@{Recipient}"; private string DebuggerDisplay => $"@{Recipient} ({Id}, DM)"; internal new SocketDMChannel Clone() => MemberwiseClone() as SocketDMChannel; + #endregion - //SocketChannel + #region SocketChannel /// internal override IReadOnlyCollection GetUsersInternal() => Users; /// internal override SocketUser GetUserInternal(ulong id) => GetUser(id); + #endregion - //IDMChannel + #region IDMChannel /// IUser IDMChannel.Recipient => Recipient; + #endregion - //ISocketPrivateChannel + #region ISocketPrivateChannel /// IReadOnlyCollection ISocketPrivateChannel.Recipients => ImmutableArray.Create(Recipient); + #endregion - //IPrivateChannel + #region IPrivateChannel /// IReadOnlyCollection IPrivateChannel.Recipients => ImmutableArray.Create(Recipient); + #endregion - //IMessageChannel + #region IMessageChannel /// async Task IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) { @@ -238,16 +255,23 @@ IAsyncEnumerable> IMessageChannel.GetMessagesAsync async Task> IMessageChannel.GetPinnedMessagesAsync(RequestOptions options) => await GetPinnedMessagesAsync(options).ConfigureAwait(false); /// - async Task IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendFileAsync(filePath, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(filePath, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + /// + async Task IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(stream, filename, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + /// + async Task IMessageChannel.SendFileAsync(FileAttachment attachment, string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(attachment, text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); /// - async Task IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendFileAsync(stream, filename, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendFilesAsync(IEnumerable attachments, string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFilesAsync(attachments, text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); /// - async Task IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + #endregion - //IChannel + #region IChannel /// string IChannel.Name => $"@{Recipient}"; @@ -257,5 +281,6 @@ Task IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions optio /// IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => ImmutableArray.Create>(Users).ToAsyncEnumerable(); + #endregion } } diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs index ab8c76aeb..1bbfa6e97 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs @@ -20,6 +20,7 @@ namespace Discord.WebSocket [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketGroupChannel : SocketChannel, IGroupChannel, ISocketPrivateChannel, ISocketMessageChannel, ISocketAudioChannel { + #region SocketGroupChannel private readonly MessageCache _messages; private readonly ConcurrentDictionary _voiceStates; @@ -31,7 +32,15 @@ public class SocketGroupChannel : SocketChannel, IGroupChannel, ISocketPrivateCh /// public IReadOnlyCollection CachedMessages => _messages?.Messages ?? ImmutableArray.Create(); + + /// + /// Returns a collection representing all of the users in the group. + /// public new IReadOnlyCollection Users => _users.ToReadOnlyCollection(); + + /// + /// Returns a collection representing all users in the group, not including the client. + /// public IReadOnlyCollection Recipients => _users.Select(x => x.Value).Where(x => x.Id != Discord.CurrentUser.Id).ToReadOnlyCollection(() => _users.Count - 1); @@ -76,8 +85,9 @@ public Task ConnectAsync() { throw new NotSupportedException("Voice is not yet supported for group channels."); } +#endregion - //Messages + #region Messages /// public SocketMessage GetCachedMessage(ulong id) => _messages?.Get(id); @@ -163,15 +173,24 @@ public Task> GetPinnedMessagesAsync(RequestOpti /// /// Message content is too long, length must be less or equal to . - public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, allowedMentions, messageReference, options); + public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); /// - public Task SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, allowedMentions, messageReference, options, isSpoiler); + public Task SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, isSpoiler, embeds); + /// + /// Message content is too long, length must be less or equal to . + public Task SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, isSpoiler, embeds); + /// + /// Message content is too long, length must be less or equal to . + public Task SendFileAsync(FileAttachment attachment, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, attachment, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); /// - public Task SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, allowedMentions, messageReference, options, isSpoiler); + /// Message content is too long, length must be less or equal to . + public Task SendFilesAsync(IEnumerable attachments, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFilesAsync(this, Discord, attachments, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); /// public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null) @@ -195,8 +214,9 @@ internal void AddMessage(SocketMessage msg) => _messages?.Add(msg); internal SocketMessage RemoveMessage(ulong id) => _messages?.Remove(id); + #endregion - //Users + #region Users /// /// Gets a user from this group. /// @@ -231,8 +251,9 @@ internal SocketGroupUser RemoveUser(ulong id) } return null; } + #endregion - //Voice States + #region Voice States internal SocketVoiceState AddOrUpdateVoiceState(ClientState state, VoiceStateModel model) { var voiceChannel = state.GetChannel(model.ChannelId.Value) as SocketVoiceChannel; @@ -259,22 +280,26 @@ internal SocketVoiceState AddOrUpdateVoiceState(ClientState state, VoiceStateMod public override string ToString() => Name; private string DebuggerDisplay => $"{Name} ({Id}, Group)"; internal new SocketGroupChannel Clone() => MemberwiseClone() as SocketGroupChannel; + #endregion - //SocketChannel + #region SocketChannel /// internal override IReadOnlyCollection GetUsersInternal() => Users; /// internal override SocketUser GetUserInternal(ulong id) => GetUser(id); + #endregion - //ISocketPrivateChannel + #region ISocketPrivateChannel /// IReadOnlyCollection ISocketPrivateChannel.Recipients => Recipients; + #endregion - //IPrivateChannel + #region IPrivateChannel /// IReadOnlyCollection IPrivateChannel.Recipients => Recipients; + #endregion - //IMessageChannel + #region IMessageChannel /// async Task IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) { @@ -297,27 +322,37 @@ async Task> IMessageChannel.GetPinnedMessagesAsync => await GetPinnedMessagesAsync(options).ConfigureAwait(false); /// - async Task IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendFileAsync(filePath, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(filePath, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); /// - async Task IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendFileAsync(stream, filename, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(stream, filename, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + /// + async Task IMessageChannel.SendFileAsync(FileAttachment attachment, string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(attachment, text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + /// + async Task IMessageChannel.SendFilesAsync(IEnumerable attachments, string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFilesAsync(attachments, text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + /// - async Task IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + #endregion - //IAudioChannel + #region IAudioChannel /// /// Connecting to a group channel is not supported. Task IAudioChannel.ConnectAsync(bool selfDeaf, bool selfMute, bool external) { throw new NotSupportedException(); } Task IAudioChannel.DisconnectAsync() { throw new NotSupportedException(); } + #endregion - //IChannel + #region IChannel /// Task IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) => Task.FromResult(GetUser(id)); /// IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => ImmutableArray.Create>(Users).ToAsyncEnumerable(); + #endregion } } diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs index 3cc8496d9..d38a8975b 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs @@ -15,6 +15,7 @@ namespace Discord.WebSocket [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketGuildChannel : SocketChannel, IGuildChannel { + #region SocketGuildChannel private ImmutableArray _overwrites; /// @@ -27,7 +28,7 @@ public class SocketGuildChannel : SocketChannel, IGuildChannel /// public string Name { get; private set; } /// - public int Position { get; private set; } + public int Position { get; private set; } /// public virtual IReadOnlyCollection PermissionOverwrites => _overwrites; @@ -46,27 +47,24 @@ internal SocketGuildChannel(DiscordSocketClient discord, ulong id, SocketGuild g } internal static SocketGuildChannel Create(SocketGuild guild, ClientState state, Model model) { - switch (model.Type) + return model.Type switch { - case ChannelType.News: - return SocketNewsChannel.Create(guild, state, model); - case ChannelType.Text: - return SocketTextChannel.Create(guild, state, model); - case ChannelType.Voice: - return SocketVoiceChannel.Create(guild, state, model); - case ChannelType.Category: - return SocketCategoryChannel.Create(guild, state, model); - default: - return new SocketGuildChannel(guild.Discord, model.Id, guild); - } + ChannelType.News => SocketNewsChannel.Create(guild, state, model), + ChannelType.Text => SocketTextChannel.Create(guild, state, model), + ChannelType.Voice => SocketVoiceChannel.Create(guild, state, model), + ChannelType.Category => SocketCategoryChannel.Create(guild, state, model), + ChannelType.PrivateThread or ChannelType.PublicThread or ChannelType.NewsThread => SocketThreadChannel.Create(guild, state, model), + ChannelType.Stage => SocketStageChannel.Create(guild, state, model), + _ => new SocketGuildChannel(guild.Discord, model.Id, guild), + }; } /// internal override void Update(ClientState state, Model model) { Name = model.Name.Value; - Position = model.Position.Value; - - var overwrites = model.PermissionOverwrites.Value; + Position = model.Position.GetValueOrDefault(0); + + var overwrites = model.PermissionOverwrites.GetValueOrDefault(new API.Overwrite[0]); var newOverwrites = ImmutableArray.CreateBuilder(overwrites.Length); for (int i = 0; i < overwrites.Length; i++) newOverwrites.Add(overwrites[i].ToEntity()); @@ -176,14 +174,16 @@ public virtual async Task RemovePermissionOverwriteAsync(IRole role, RequestOpti public override string ToString() => Name; private string DebuggerDisplay => $"{Name} ({Id}, Guild)"; internal new SocketGuildChannel Clone() => MemberwiseClone() as SocketGuildChannel; +#endregion - //SocketChannel + #region SocketChannel /// internal override IReadOnlyCollection GetUsersInternal() => Users; /// internal override SocketUser GetUserInternal(ulong id) => GetUser(id); + #endregion - //IGuildChannel + #region IGuildChannel /// IGuild IGuildChannel.Guild => Guild; /// @@ -214,13 +214,15 @@ IAsyncEnumerable> IGuildChannel.GetUsersAsync(Ca /// Task IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) => Task.FromResult(GetUser(id)); + #endregion - //IChannel + #region IChannel /// IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => ImmutableArray.Create>(Users).ToAsyncEnumerable(); //Overridden in Text/Voice /// Task IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) => Task.FromResult(GetUser(id)); //Overridden in Text/Voice + #endregion } } diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketStageChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketStageChannel.cs new file mode 100644 index 000000000..91bca5054 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketStageChannel.cs @@ -0,0 +1,158 @@ +using Discord.Rest; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using Model = Discord.API.Channel; +using StageInstance = Discord.API.StageInstance; + +namespace Discord.WebSocket +{ + /// + /// Represents a stage channel received over the gateway. + /// + public class SocketStageChannel : SocketVoiceChannel, IStageChannel + { + /// + public string Topic { get; private set; } + + /// + public StagePrivacyLevel? PrivacyLevel { get; private set; } + + /// + public bool? IsDiscoverableDisabled { get; private set; } + + /// + public bool IsLive { get; private set; } + + /// + /// Returns if the current user is a speaker within the stage, otherwise . + /// + public bool IsSpeaker + => !Guild.CurrentUser.IsSuppressed; + + /// + /// Gets a collection of users who are speakers within the stage. + /// + public IReadOnlyCollection Speakers + => Users.Where(x => !x.IsSuppressed).ToImmutableArray(); + + internal new SocketStageChannel Clone() => MemberwiseClone() as SocketStageChannel; + + internal SocketStageChannel(DiscordSocketClient discord, ulong id, SocketGuild guild) + : base(discord, id, guild) { } + + internal new static SocketStageChannel Create(SocketGuild guild, ClientState state, Model model) + { + var entity = new SocketStageChannel(guild.Discord, model.Id, guild); + entity.Update(state, model); + return entity; + } + + internal void Update(StageInstance model, bool isLive = false) + { + IsLive = isLive; + if (isLive) + { + Topic = model.Topic; + PrivacyLevel = model.PrivacyLevel; + IsDiscoverableDisabled = model.DiscoverableDisabled; + } + else + { + Topic = null; + PrivacyLevel = null; + IsDiscoverableDisabled = null; + } + } + + /// + public async Task StartStageAsync(string topic, StagePrivacyLevel privacyLevel = StagePrivacyLevel.GuildOnly, RequestOptions options = null) + { + var args = new API.Rest.CreateStageInstanceParams + { + ChannelId = Id, + Topic = topic, + PrivacyLevel = privacyLevel + }; + + var model = await Discord.ApiClient.CreateStageInstanceAsync(args, options).ConfigureAwait(false); + + Update(model, true); + } + + /// + public async Task ModifyInstanceAsync(Action func, RequestOptions options = null) + { + var model = await ChannelHelper.ModifyAsync(this, Discord, func, options); + + Update(model, true); + } + + /// + public async Task StopStageAsync(RequestOptions options = null) + { + await Discord.ApiClient.DeleteStageInstanceAsync(Id, options); + + Update(null); + } + + /// + public Task RequestToSpeakAsync(RequestOptions options = null) + { + var args = new API.Rest.ModifyVoiceStateParams + { + ChannelId = Id, + RequestToSpeakTimestamp = DateTimeOffset.UtcNow + }; + return Discord.ApiClient.ModifyMyVoiceState(Guild.Id, args, options); + } + + /// + public Task BecomeSpeakerAsync(RequestOptions options = null) + { + var args = new API.Rest.ModifyVoiceStateParams + { + ChannelId = Id, + Suppressed = false + }; + return Discord.ApiClient.ModifyMyVoiceState(Guild.Id, args, options); + } + + /// + public Task StopSpeakingAsync(RequestOptions options = null) + { + var args = new API.Rest.ModifyVoiceStateParams + { + ChannelId = Id, + Suppressed = true + }; + return Discord.ApiClient.ModifyMyVoiceState(Guild.Id, args, options); + } + + /// + public Task MoveToSpeakerAsync(IGuildUser user, RequestOptions options = null) + { + var args = new API.Rest.ModifyVoiceStateParams + { + ChannelId = Id, + Suppressed = false + }; + + return Discord.ApiClient.ModifyUserVoiceState(Guild.Id, user.Id, args); + } + + /// + public Task RemoveFromSpeakerAsync(IGuildUser user, RequestOptions options = null) + { + var args = new API.Rest.ModifyVoiceStateParams + { + ChannelId = Id, + Suppressed = true + }; + + return Discord.ApiClient.ModifyUserVoiceState(Guild.Id, user.Id, args); + } + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs index 71a20c198..8722b569d 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs @@ -16,6 +16,7 @@ namespace Discord.WebSocket [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketTextChannel : SocketGuildChannel, ITextChannel, ISocketMessageChannel { + #region SocketTextChannel private readonly MessageCache _messages; /// @@ -50,6 +51,12 @@ public override IReadOnlyCollection Users Permissions.ResolveChannel(Guild, x, this, Permissions.ResolveGuild(Guild, x)), ChannelPermission.ViewChannel)).ToImmutableArray(); + /// + /// Gets a collection of threads within this text channel. + /// + public IReadOnlyCollection Threads + => Guild.ThreadChannels.Where(x => x.ParentChannel.Id == Id).ToImmutableArray(); + internal SocketTextChannel(DiscordSocketClient discord, ulong id, SocketGuild guild) : base(discord, id, guild) { @@ -66,16 +73,59 @@ internal override void Update(ClientState state, Model model) { base.Update(state, model); CategoryId = model.CategoryId; - Topic = model.Topic.Value; + Topic = model.Topic.GetValueOrDefault(); SlowModeInterval = model.SlowMode.GetValueOrDefault(); // some guilds haven't been patched to include this yet? _nsfw = model.Nsfw.GetValueOrDefault(); } /// - public Task ModifyAsync(Action func, RequestOptions options = null) + public virtual Task ModifyAsync(Action func, RequestOptions options = null) => ChannelHelper.ModifyAsync(this, Discord, func, options); - //Messages + /// + /// Creates a thread within this . + /// + /// + /// When is the thread type will be based off of the + /// channel its created in. When called on a , it creates a . + /// When called on a , it creates a . The id of the created + /// thread will be the same as the id of the message, and as such a message can only have a + /// single thread created from it. + /// + /// The name of the thread. + /// + /// The type of the thread. + /// + /// Note: This parameter is not used if the parameter is not specified. + /// + /// + /// + /// The duration on which this thread archives after. + /// + /// Note: Options and + /// are only available for guilds that are boosted. You can check in the to see if the + /// guild has the THREE_DAY_THREAD_ARCHIVE and SEVEN_DAY_THREAD_ARCHIVE. + /// + /// + /// The message which to start the thread from. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous create operation. The task result contains a + /// + public async Task CreateThreadAsync(string name, ThreadType type = ThreadType.PublicThread, + ThreadArchiveDuration autoArchiveDuration = ThreadArchiveDuration.OneDay, IMessage message = null, bool? invitable = null, int? slowmode = null, RequestOptions options = null) + { + var model = await ThreadHelper.CreateThreadAsync(Discord, this, name, type, autoArchiveDuration, message, invitable, slowmode, options); + + var thread = (SocketThreadChannel)Guild.AddOrUpdateChannel(Discord.State, model); + + await thread.DownloadUsersAsync(); + + return thread; + } +#endregion + + #region Messages /// public SocketMessage GetCachedMessage(ulong id) => _messages?.Get(id); @@ -161,17 +211,27 @@ public Task> GetPinnedMessagesAsync(RequestOpti /// /// Message content is too long, length must be less or equal to . - public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, allowedMentions, messageReference, options); + public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); /// - public Task SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, allowedMentions, messageReference, options, isSpoiler); + public Task SendFileAsync(string filePath, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, isSpoiler, embeds); /// /// Message content is too long, length must be less or equal to . - public Task SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, allowedMentions, messageReference, options, isSpoiler); + public Task SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, isSpoiler, embeds); + + /// + /// Message content is too long, length must be less or equal to . + public Task SendFileAsync(FileAttachment attachment, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFileAsync(this, Discord, attachment, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); + + /// + /// Message content is too long, length must be less or equal to . + public Task SendFilesAsync(IEnumerable attachments, string text, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) + => ChannelHelper.SendFilesAsync(this, Discord, attachments, text, isTTS, embed, allowedMentions, messageReference, component, stickers, options, embeds); /// public Task DeleteMessagesAsync(IEnumerable messages, RequestOptions options = null) @@ -202,8 +262,9 @@ internal void AddMessage(SocketMessage msg) => _messages?.Add(msg); internal SocketMessage RemoveMessage(ulong id) => _messages?.Remove(id); + #endregion - //Users + #region Users /// public override SocketGuildUser GetUser(ulong id) { @@ -217,8 +278,9 @@ public override SocketGuildUser GetUser(ulong id) } return null; } + #endregion - //Webhooks + #region Webhooks /// /// Creates a webhook in this text channel. /// @@ -229,7 +291,7 @@ public override SocketGuildUser GetUser(ulong id) /// A task that represents the asynchronous creation operation. The task result contains the newly created /// webhook. /// - public Task CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null) + public virtual Task CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null) => ChannelHelper.CreateWebhookAsync(this, Discord, name, avatar, options); /// /// Gets a webhook available in this text channel. @@ -240,7 +302,7 @@ public Task CreateWebhookAsync(string name, Stream avatar = null, R /// A task that represents the asynchronous get operation. The task result contains a webhook associated /// with the identifier; null if the webhook is not found. /// - public Task GetWebhookAsync(ulong id, RequestOptions options = null) + public virtual Task GetWebhookAsync(ulong id, RequestOptions options = null) => ChannelHelper.GetWebhookAsync(this, Discord, id, options); /// /// Gets the webhooks available in this text channel. @@ -250,21 +312,29 @@ public Task GetWebhookAsync(ulong id, RequestOptions options = null /// A task that represents the asynchronous get operation. The task result contains a read-only collection /// of webhooks that is available in this channel. /// - public Task> GetWebhooksAsync(RequestOptions options = null) + public virtual Task> GetWebhooksAsync(RequestOptions options = null) => ChannelHelper.GetWebhooksAsync(this, Discord, options); + #endregion - //Invites + #region Invites /// - public async Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + public virtual async Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); /// - public async Task> GetInvitesAsync(RequestOptions options = null) + public virtual async Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options).ConfigureAwait(false); + /// + public virtual async Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToStreamAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, user, options).ConfigureAwait(false); + /// + public virtual async Task> GetInvitesAsync(RequestOptions options = null) => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); private string DebuggerDisplay => $"{Name} ({Id}, Text)"; internal new SocketTextChannel Clone() => MemberwiseClone() as SocketTextChannel; + #endregion - //ITextChannel + #region ITextChannel /// async Task ITextChannel.CreateWebhookAsync(string name, Stream avatar, RequestOptions options) => await CreateWebhookAsync(name, avatar, options).ConfigureAwait(false); @@ -274,16 +344,21 @@ async Task ITextChannel.GetWebhookAsync(ulong id, RequestOptions optio /// async Task> ITextChannel.GetWebhooksAsync(RequestOptions options) => await GetWebhooksAsync(options).ConfigureAwait(false); + /// + async Task ITextChannel.CreateThreadAsync(string name, ThreadType type, ThreadArchiveDuration autoArchiveDuration, IMessage message, bool? invitable, int? slowmode, RequestOptions options) + => await CreateThreadAsync(name, type, autoArchiveDuration, message, invitable, slowmode, options); + #endregion - //IGuildChannel + #region IGuildChannel /// Task IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) => Task.FromResult(GetUser(id)); /// IAsyncEnumerable> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => ImmutableArray.Create>(Users).ToAsyncEnumerable(); + #endregion - //IMessageChannel + #region IMessageChannel /// async Task IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) { @@ -306,18 +381,26 @@ async Task> IMessageChannel.GetPinnedMessagesAsync => await GetPinnedMessagesAsync(options).ConfigureAwait(false); /// - async Task IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendFileAsync(filePath, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(filePath, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + /// + async Task IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(stream, filename, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + /// + async Task IMessageChannel.SendFileAsync(FileAttachment attachment, string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFileAsync(attachment, text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); /// - async Task IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, Embed embed, RequestOptions options, bool isSpoiler, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendFileAsync(stream, filename, text, isTTS, embed, options, isSpoiler, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendFilesAsync(IEnumerable attachments, string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendFilesAsync(attachments, text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); /// - async Task IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference) - => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference).ConfigureAwait(false); + async Task IMessageChannel.SendMessageAsync(string text, bool isTTS, Embed embed, RequestOptions options, AllowedMentions allowedMentions, MessageReference messageReference, MessageComponent component, ISticker[] stickers, Embed[] embeds) + => await SendMessageAsync(text, isTTS, embed, options, allowedMentions, messageReference, component, stickers, embeds).ConfigureAwait(false); + #endregion - // INestedChannel + #region INestedChannel /// Task INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options) => Task.FromResult(Category); + #endregion } } diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketThreadChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketThreadChannel.cs new file mode 100644 index 000000000..7fcafc14a --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketThreadChannel.cs @@ -0,0 +1,339 @@ +using Discord.Rest; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Model = Discord.API.Channel; +using ThreadMember = Discord.API.ThreadMember; +using System.Collections.Concurrent; + +namespace Discord.WebSocket +{ + /// + /// Represents a thread channel inside of a guild. + /// + [DebuggerDisplay(@"{DebuggerDisplay,nq}")] + public class SocketThreadChannel : SocketTextChannel, IThreadChannel + { + /// + public ThreadType Type { get; private set; } + + /// + /// Gets the owner of the current thread. + /// + public SocketThreadUser Owner { get; private set; } + + /// + /// Gets the current users within this thread. + /// + public SocketThreadUser CurrentUser + => Users.FirstOrDefault(x => x.Id == Discord.CurrentUser.Id); + + /// + public bool HasJoined { get; private set; } + + /// + /// if this thread is private, otherwise + /// + public bool IsPrivateThread + => Type == ThreadType.PrivateThread; + + /// + /// Gets the parent channel this thread resides in. + /// + public SocketTextChannel ParentChannel { get; private set; } + + /// + public int MessageCount { get; private set; } + + /// + public int MemberCount { get; private set; } + + /// + public bool IsArchived { get; private set; } + + /// + public DateTimeOffset ArchiveTimestamp { get; private set; } + + /// + public ThreadArchiveDuration AutoArchiveDuration { get; private set; } + + /// + public bool IsLocked { get; private set; } + + /// + /// Gets a collection of cached users within this thread. + /// + public new IReadOnlyCollection Users => + _members.Values.ToImmutableArray(); + + private readonly ConcurrentDictionary _members; + + private string DebuggerDisplay => $"{Name} ({Id}, Thread)"; + + private bool _usersDownloaded; + + private readonly object _downloadLock = new object(); + + internal SocketThreadChannel(DiscordSocketClient discord, SocketGuild guild, ulong id, SocketTextChannel parent) + : base(discord, id, guild) + { + ParentChannel = parent; + _members = new ConcurrentDictionary(); + } + + internal new static SocketThreadChannel Create(SocketGuild guild, ClientState state, Model model) + { + var parent = (SocketTextChannel)guild.GetChannel(model.CategoryId.Value); + var entity = new SocketThreadChannel(guild.Discord, guild, model.Id, parent); + entity.Update(state, model); + return entity; + } + + internal override void Update(ClientState state, Model model) + { + base.Update(state, model); + + Type = (ThreadType)model.Type; + MessageCount = model.MessageCount.GetValueOrDefault(-1); + MemberCount = model.MemberCount.GetValueOrDefault(-1); + + if (model.ThreadMetadata.IsSpecified) + { + IsArchived = model.ThreadMetadata.Value.Archived; + ArchiveTimestamp = model.ThreadMetadata.Value.ArchiveTimestamp; + AutoArchiveDuration = model.ThreadMetadata.Value.AutoArchiveDuration; + IsLocked = model.ThreadMetadata.Value.Locked.GetValueOrDefault(false); + } + + if (model.OwnerId.IsSpecified) + { + Owner = GetUser(model.OwnerId.Value); + } + + HasJoined = model.ThreadMember.IsSpecified; + } + + internal IReadOnlyCollection RemoveUsers(ulong[] users) + { + List threadUsers = new(); + + foreach (var userId in users) + { + if (_members.TryRemove(userId, out var user)) + threadUsers.Add(user); + } + + return threadUsers.ToImmutableArray(); + } + + internal SocketThreadUser AddOrUpdateThreadMember(ThreadMember model, SocketGuildUser guildMember) + { + if (_members.TryGetValue(model.UserId.Value, out SocketThreadUser member)) + member.Update(model); + else + { + member = SocketThreadUser.Create(Guild, this, model, guildMember); + member.GlobalUser.AddRef(); + _members[member.Id] = member; + } + return member; + } + + /// + public new SocketThreadUser GetUser(ulong id) + { + var user = Users.FirstOrDefault(x => x.Id == id); + return user; + } + + /// + /// Gets all users inside this thread. + /// + /// + /// If all users are not downloaded then this method will call and return the result. + /// + /// The options to be used when sending the request. + /// A task representing the download operation. + public async Task> GetUsersAsync(RequestOptions options = null) + { + // download all users if we havent + if (!_usersDownloaded) + { + await DownloadUsersAsync(options); + _usersDownloaded = true; + } + + return Users; + } + + /// + /// Downloads all users that have access to this thread. + /// + /// The options to be used when sending the request. + /// A task representing the asynchronous download operation. + public async Task DownloadUsersAsync(RequestOptions options = null) + { + var users = await Discord.ApiClient.ListThreadMembersAsync(Id, options); + + lock (_downloadLock) + { + foreach (var threadMember in users) + { + var guildUser = Guild.GetUser(threadMember.UserId.Value); + + AddOrUpdateThreadMember(threadMember, guildUser); + } + } + } + + internal new SocketThreadChannel Clone() => MemberwiseClone() as SocketThreadChannel; + + /// + public Task JoinAsync(RequestOptions options = null) + => Discord.ApiClient.JoinThreadAsync(Id, options); + + /// + public Task LeaveAsync(RequestOptions options = null) + => Discord.ApiClient.LeaveThreadAsync(Id, options); + + /// + /// Adds a user to this thread. + /// + /// The to add. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous operation of adding a member to a thread. + /// + public Task AddUserAsync(IGuildUser user, RequestOptions options = null) + => Discord.ApiClient.AddThreadMemberAsync(Id, user.Id, options); + + /// + /// Removes a user from this thread. + /// + /// The to remove from this thread. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous operation of removing a user from this thread. + /// + public Task RemoveUserAsync(IGuildUser user, RequestOptions options = null) + => Discord.ApiClient.RemoveThreadMemberAsync(Id, user.Id, options); + + /// + /// + /// This method is not supported in threads. + /// + public override Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task AddPermissionOverwriteAsync(IUser user, OverwritePermissions permissions, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task> GetInvitesAsync(RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override OverwritePermissions? GetPermissionOverwrite(IRole role) + => ParentChannel.GetPermissionOverwrite(role); + + /// + /// + /// This method is not supported in threads. + /// + public override OverwritePermissions? GetPermissionOverwrite(IUser user) + => ParentChannel.GetPermissionOverwrite(user); + + /// + /// + /// This method is not supported in threads. + /// + public override Task GetWebhookAsync(ulong id, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task> GetWebhooksAsync(RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task ModifyAsync(Action func, RequestOptions options = null) + => ThreadHelper.ModifyAsync(this, Discord, func, options); + + /// + /// + /// This method is not supported in threads. + /// + public override Task RemovePermissionOverwriteAsync(IRole role, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task RemovePermissionOverwriteAsync(IUser user, RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override IReadOnlyCollection PermissionOverwrites + => throw new NotSupportedException("This method is not supported in threads."); + + /// + /// + /// This method is not supported in threads. + /// + public override Task SyncPermissionsAsync(RequestOptions options = null) + => throw new NotSupportedException("This method is not supported in threads."); + + string IChannel.Name => Name; + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs index ecaccedd3..e57051e80 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs @@ -16,6 +16,7 @@ namespace Discord.WebSocket [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketVoiceChannel : SocketGuildChannel, IVoiceChannel, ISocketAudioChannel { + #region SocketVoiceChannel /// public int Bitrate { get; private set; } /// @@ -89,29 +90,39 @@ public override SocketGuildUser GetUser(ulong id) return user; return null; } +#endregion - //Invites + #region Invites /// public async Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); /// + public async Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options).ConfigureAwait(false); + /// + public async Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToStreamAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, user, options).ConfigureAwait(false); + /// public async Task> GetInvitesAsync(RequestOptions options = null) => await ChannelHelper.GetInvitesAsync(this, Discord, options).ConfigureAwait(false); private string DebuggerDisplay => $"{Name} ({Id}, Voice)"; internal new SocketVoiceChannel Clone() => MemberwiseClone() as SocketVoiceChannel; + #endregion - //IGuildChannel + #region IGuildChannel /// Task IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) => Task.FromResult(GetUser(id)); /// IAsyncEnumerable> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) => ImmutableArray.Create>(Users).ToAsyncEnumerable(); + #endregion - // INestedChannel + #region INestedChannel /// Task INestedChannel.GetCategoryAsync(CacheMode mode, RequestOptions options) => Task.FromResult(Category); + #endregion } } diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs index 9af4ad57e..beaab1cfe 100644 --- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -19,6 +19,9 @@ using RoleModel = Discord.API.Role; using UserModel = Discord.API.User; using VoiceStateModel = Discord.API.VoiceState; +using StickerModel = Discord.API.Sticker; +using EventModel = Discord.API.GuildScheduledEvent; +using System.IO; namespace Discord.WebSocket { @@ -28,16 +31,19 @@ namespace Discord.WebSocket [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketGuild : SocketEntity, IGuild, IDisposable { + #region SocketGuild #pragma warning disable IDISP002, IDISP006 private readonly SemaphoreSlim _audioLock; private TaskCompletionSource _syncPromise, _downloaderPromise; private TaskCompletionSource _audioConnectPromise; - private ConcurrentHashSet _channels; + private ConcurrentDictionary _channels; private ConcurrentDictionary _members; private ConcurrentDictionary _roles; private ConcurrentDictionary _voiceStates; + private ConcurrentDictionary _stickers; + private ConcurrentDictionary _events; private ImmutableArray _emotes; - private ImmutableArray _features; + private AudioClient _audioClient; #pragma warning restore IDISP002, IDISP006 @@ -118,9 +124,14 @@ public class SocketGuild : SocketEntity, IGuild, IDisposable public int? MaxMembers { get; private set; } /// public int? MaxVideoChannelUsers { get; private set; } - + /// + public NsfwLevel NsfwLevel { get; private set; } /// public CultureInfo PreferredCulture { get; private set; } + /// + public bool IsBoostProgressBarEnabled { get; private set; } + /// + public GuildFeatures Features { get; private set; } /// public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); @@ -131,7 +142,7 @@ public class SocketGuild : SocketEntity, IGuild, IDisposable /// public string DiscoverySplashUrl => CDN.GetGuildDiscoverySplashUrl(Id, DiscoverySplashId); /// - public string BannerUrl => CDN.GetGuildBannerUrl(Id, BannerId); + public string BannerUrl => CDN.GetGuildBannerUrl(Id, BannerId, ImageFormat.Auto); /// Indicates whether the client has all the members downloaded to the local guild cache. public bool HasAllMembers => MemberCount <= DownloadedMemberCount;// _downloaderPromise.Task.IsCompleted; /// Indicates whether the guild cache is synced to this guild. @@ -269,6 +280,14 @@ public IReadOnlyCollection TextChannels public IReadOnlyCollection VoiceChannels => Channels.OfType().ToImmutableArray(); /// + /// Gets a collection of all stage channels in this guild. + /// + /// + /// A read-only collection of stage channels found within this guild. + /// + public IReadOnlyCollection StageChannels + => Channels.OfType().ToImmutableArray(); + /// /// Gets a collection of all category channels in this guild. /// /// @@ -277,6 +296,14 @@ public IReadOnlyCollection VoiceChannels public IReadOnlyCollection CategoryChannels => Channels.OfType().ToImmutableArray(); /// + /// Gets a collection of all thread channels in this guild. + /// + /// + /// A read-only collection of thread channels found within this guild. + /// + public IReadOnlyCollection ThreadChannels + => Channels.OfType().ToImmutableArray(); + /// /// Gets the current logged-in user. /// public SocketGuildUser CurrentUser => _members.TryGetValue(Discord.CurrentUser.Id, out SocketGuildUser member) ? member : null; @@ -299,13 +326,16 @@ public IReadOnlyCollection Channels { var channels = _channels; var state = Discord.State; - return channels.Select(x => state.GetChannel(x) as SocketGuildChannel).Where(x => x != null).ToReadOnlyCollection(channels); + return channels.Select(x => x.Value).Where(x => x != null).ToReadOnlyCollection(channels); } } /// public IReadOnlyCollection Emotes => _emotes; - /// - public IReadOnlyCollection Features => _features; + /// + /// Gets a collection of all custom stickers for this guild. + /// + public IReadOnlyCollection Stickers + => _stickers.Select(x => x.Value).ToImmutableArray(); /// /// Gets a collection of users in this guild. /// @@ -336,12 +366,22 @@ public IReadOnlyCollection Channels /// public IReadOnlyCollection Roles => _roles.ToReadOnlyCollection(); + /// + /// Gets a collection of all events within this guild. + /// + /// + /// This field is based off of caching alone, since there is no events returned on the guild model. + /// + /// + /// A read-only collection of guild events found within this guild. + /// + public IReadOnlyCollection Events => _events.ToReadOnlyCollection(); + internal SocketGuild(DiscordSocketClient client, ulong id) : base(client, id) { _audioLock = new SemaphoreSlim(1, 1); _emotes = ImmutableArray.Create(); - _features = ImmutableArray.Create(); } internal static SocketGuild Create(DiscordSocketClient discord, ClientState state, ExtendedModel model) { @@ -354,8 +394,10 @@ internal void Update(ClientState state, ExtendedModel model) IsAvailable = !(model.Unavailable ?? false); if (!IsAvailable) { + if(_events == null) + _events = new ConcurrentDictionary(); if (_channels == null) - _channels = new ConcurrentHashSet(); + _channels = new ConcurrentDictionary(); if (_members == null) _members = new ConcurrentDictionary(); if (_roles == null) @@ -371,15 +413,23 @@ internal void Update(ClientState state, ExtendedModel model) Update(state, model as Model); - var channels = new ConcurrentHashSet(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(model.Channels.Length * 1.05)); + var channels = new ConcurrentDictionary(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(model.Channels.Length * 1.05)); { for (int i = 0; i < model.Channels.Length; i++) { var channel = SocketGuildChannel.Create(this, state, model.Channels[i]); state.AddChannel(channel); - channels.TryAdd(channel.Id); + channels.TryAdd(channel.Id, channel); + } + + for(int i = 0; i < model.Threads.Length; i++) + { + var threadChannel = SocketThreadChannel.Create(this, state, model.Threads[i]); + state.AddChannel(threadChannel); + channels.TryAdd(threadChannel.Id, threadChannel); } } + _channels = channels; var members = new ConcurrentDictionary(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(model.Members.Length * 1.05)); @@ -414,6 +464,17 @@ internal void Update(ClientState state, ExtendedModel model) } _voiceStates = voiceStates; + var events = new ConcurrentDictionary(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(model.GuildScheduledEvents.Length * 1.05)); + { + for (int i = 0; i < model.GuildScheduledEvents.Length; i++) + { + var guildEvent = SocketGuildEvent.Create(Discord, this, model.GuildScheduledEvents[i]); + events.TryAdd(guildEvent.Id, guildEvent); + } + } + _events = events; + + _syncPromise = new TaskCompletionSource(); _downloaderPromise = new TaskCompletionSource(); var _ = _syncPromise.TrySetResultAsync(true); @@ -448,6 +509,7 @@ internal void Update(ClientState state, Model model) SystemChannelFlags = model.SystemChannelFlags; Description = model.Description; PremiumSubscriptionCount = model.PremiumSubscriptionCount.GetValueOrDefault(); + NsfwLevel = model.NsfwLevel; if (model.MaxPresences.IsSpecified) MaxPresences = model.MaxPresences.Value ?? 25000; if (model.MaxMembers.IsSpecified) @@ -456,7 +518,8 @@ internal void Update(ClientState state, Model model) MaxVideoChannelUsers = model.MaxVideoChannelUsers.Value; PreferredLocale = model.PreferredLocale; PreferredCulture = PreferredLocale == null ? null : new CultureInfo(PreferredLocale); - + if (model.IsBoostProgressBarEnabled.IsSpecified) + IsBoostProgressBarEnabled = model.IsBoostProgressBarEnabled.Value; if (model.Emojis != null) { var emojis = ImmutableArray.CreateBuilder(model.Emojis.Length); @@ -467,10 +530,7 @@ internal void Update(ClientState state, Model model) else _emotes = ImmutableArray.Create(); - if (model.Features != null) - _features = model.Features.ToImmutableArray(); - else - _features = ImmutableArray.Create(); + Features = model.Features; var roles = new ConcurrentDictionary(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(model.Roles.Length * 1.05)); if (model.Roles != null) @@ -482,6 +542,25 @@ internal void Update(ClientState state, Model model) } } _roles = roles; + + if (model.Stickers != null) + { + var stickers = new ConcurrentDictionary(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(model.Stickers.Length * 1.05)); + for (int i = 0; i < model.Stickers.Length; i++) + { + var sticker = model.Stickers[i]; + if (sticker.User.IsSpecified) + AddOrUpdateUser(sticker.User.Value); + + var entity = SocketCustomSticker.Create(Discord, sticker, this, sticker.User.IsSpecified ? sticker.User.Value.Id : null); + + stickers.TryAdd(sticker.Id, entity); + } + + _stickers = stickers; + } + else + _stickers = new ConcurrentDictionary(ConcurrentHashSet.DefaultConcurrencyLevel, 7); } /*internal void Update(ClientState state, GuildSyncModel model) //TODO remove? userbot related { @@ -514,8 +593,9 @@ internal void Update(ClientState state, EmojiUpdateModel model) emotes.Add(model.Emojis[i].ToEntity()); _emotes = emotes.ToImmutable(); } + #endregion - //General + #region General /// public Task DeleteAsync(RequestOptions options = null) => GuildHelper.DeleteAsync(this, Discord, options); @@ -539,8 +619,9 @@ public Task ReorderRolesAsync(IEnumerable args, RequestOp /// public Task LeaveAsync(RequestOptions options = null) => GuildHelper.LeaveAsync(this, Discord, options); + #endregion - //Bans + #region Bans /// /// Gets a collection of all users banned in this guild. /// @@ -588,8 +669,9 @@ public Task RemoveBanAsync(IUser user, RequestOptions options = null) /// public Task RemoveBanAsync(ulong userId, RequestOptions options = null) => GuildHelper.RemoveBanAsync(this, Discord, userId, options); + #endregion - //Channels + #region Channels /// /// Gets a channel in this guild. /// @@ -614,6 +696,16 @@ public SocketGuildChannel GetChannel(ulong id) public SocketTextChannel GetTextChannel(ulong id) => GetChannel(id) as SocketTextChannel; /// + /// Gets a thread in this guild. + /// + /// The snowflake identifier for the thread. + /// + /// A thread channel associated with the specified ; if none is found. + /// + public SocketThreadChannel GetThreadChannel(ulong id) + => GetChannel(id) as SocketThreadChannel; + + /// /// Gets a voice channel in this guild. /// /// The snowflake identifier for the voice channel. @@ -623,6 +715,15 @@ public SocketTextChannel GetTextChannel(ulong id) public SocketVoiceChannel GetVoiceChannel(ulong id) => GetChannel(id) as SocketVoiceChannel; /// + /// Gets a stage channel in this guild. + /// + /// The snowflake identifier for the stage channel. + /// + /// A stage channel associated with the specified ; if none is found. + /// + public SocketStageChannel GetStageChannel(ulong id) + => GetChannel(id) as SocketStageChannel; + /// /// Gets a category channel in this guild. /// /// The snowflake identifier for the category channel. @@ -670,6 +771,19 @@ public Task CreateTextChannelAsync(string name, Action public Task CreateVoiceChannelAsync(string name, Action func = null, RequestOptions options = null) => GuildHelper.CreateVoiceChannelAsync(this, Discord, name, options, func); + + /// + /// Creates a new stage channel in this guild. + /// + /// The new name for the stage channel. + /// The delegate containing the properties to be applied to the channel upon its creation. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the newly created + /// stage channel. + /// + public Task CreateStageChannelAsync(string name, Action func = null, RequestOptions options = null) + => GuildHelper.CreateStageChannelAsync(this, Discord, name, options, func); /// /// Creates a new channel category in this guild. /// @@ -687,25 +801,40 @@ public Task CreateCategoryChannelAsync(string name, Action< internal SocketGuildChannel AddChannel(ClientState state, ChannelModel model) { var channel = SocketGuildChannel.Create(this, state, model); - _channels.TryAdd(model.Id); + _channels.TryAdd(model.Id, channel); state.AddChannel(channel); return channel; } + + internal SocketGuildChannel AddOrUpdateChannel(ClientState state, ChannelModel model) + { + if (_channels.TryGetValue(model.Id, out SocketGuildChannel channel)) + channel.Update(Discord.State, model); + else + { + channel = SocketGuildChannel.Create(this, Discord.State, model); + _channels[channel.Id] = channel; + state.AddChannel(channel); + } + return channel; + } + internal SocketGuildChannel RemoveChannel(ClientState state, ulong id) { - if (_channels.TryRemove(id)) + if (_channels.TryRemove(id, out var _)) return state.RemoveChannel(id) as SocketGuildChannel; return null; } internal void PurgeChannelCache(ClientState state) { foreach (var channelId in _channels) - state.RemoveChannel(channelId); + state.RemoveChannel(channelId.Key); _channels.Clear(); } + #endregion - //Voice Regions + #region Voice Regions /// /// Gets a collection of all the voice regions this guild can access. /// @@ -716,14 +845,124 @@ internal void PurgeChannelCache(ClientState state) /// public Task> GetVoiceRegionsAsync(RequestOptions options = null) => GuildHelper.GetVoiceRegionsAsync(this, Discord, options); + #endregion - //Integrations + #region Integrations public Task> GetIntegrationsAsync(RequestOptions options = null) => GuildHelper.GetIntegrationsAsync(this, Discord, options); public Task CreateIntegrationAsync(ulong id, string type, RequestOptions options = null) => GuildHelper.CreateIntegrationAsync(this, Discord, id, type, options); + #endregion - //Invites + #region Interactions + /// + /// Deletes all application commands in the current guild. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous delete operation. + /// + public Task DeleteApplicationCommandsAsync(RequestOptions options = null) + => InteractionHelper.DeleteAllGuildCommandsAsync(Discord, Id, options); + + /// + /// Gets a collection of slash commands created by the current user in this guild. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection of + /// slash commands created by the current user. + /// + public async Task> GetApplicationCommandsAsync(RequestOptions options = null) + { + var commands = (await Discord.ApiClient.GetGuildApplicationCommandsAsync(Id, options)).Select(x => SocketApplicationCommand.Create(Discord, x, Id)); + + foreach (var command in commands) + { + Discord.State.AddCommand(command); + } + + return commands.ToImmutableArray(); + } + + /// + /// Gets an application command within this guild with the specified id. + /// + /// The id of the application command to get. + /// The that determines whether the object should be fetched from cache. + /// The options to be used when sending the request. + /// + /// A ValueTask that represents the asynchronous get operation. The task result contains a + /// if found, otherwise . + /// + public async ValueTask GetApplicationCommandAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) + { + var command = Discord.State.GetCommand(id); + + if (command != null) + return command; + + if (mode == CacheMode.CacheOnly) + return null; + + var model = await Discord.ApiClient.GetGlobalApplicationCommandAsync(id, options); + + if (model == null) + return null; + + command = SocketApplicationCommand.Create(Discord, model, Id); + + Discord.State.AddCommand(command); + + return command; + } + + /// + /// Creates an application command within this guild. + /// + /// The properties to use when creating the command. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the command that was created. + /// + public async Task CreateApplicationCommandAsync(ApplicationCommandProperties properties, RequestOptions options = null) + { + var model = await InteractionHelper.CreateGuildCommandAsync(Discord, Id, properties, options); + + var entity = Discord.State.GetOrAddCommand(model.Id, (id) => SocketApplicationCommand.Create(Discord, model)); + + entity.Update(model); + + return entity; + } + + /// + /// Overwrites the application commands within this guild. + /// + /// A collection of properties to use when creating the commands. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains a collection of commands that was created. + /// + public async Task> BulkOverwriteApplicationCommandAsync(ApplicationCommandProperties[] properties, + RequestOptions options = null) + { + var models = await InteractionHelper.BulkOverwriteGuildCommandsAsync(Discord, Id, properties, options); + + var entities = models.Select(x => SocketApplicationCommand.Create(Discord, x)); + + Discord.State.PurgeCommands(x => !x.IsGlobalCommand && x.Guild.Id == Id); + + foreach(var entity in entities) + { + Discord.State.AddCommand(entity); + } + + return entities.ToImmutableArray(); + } + #endregion + + #region Invites /// /// Gets a collection of all invites in this guild. /// @@ -744,8 +983,9 @@ public Task> GetInvitesAsync(RequestOpti /// public Task GetVanityInviteAsync(RequestOptions options = null) => GuildHelper.GetVanityInviteAsync(this, Discord, options); + #endregion - //Roles + #region Roles /// /// Gets a role in this guild. /// @@ -794,7 +1034,45 @@ internal SocketRole RemoveRole(ulong id) return null; } - //Users + internal SocketRole AddOrUpdateRole(RoleModel model) + { + if (_roles.TryGetValue(model.Id, out SocketRole role)) + _roles[model.Id].Update(Discord.State, model); + else + role = AddRole(model); + + return role; + } + + internal SocketCustomSticker AddSticker(StickerModel model) + { + if (model.User.IsSpecified) + AddOrUpdateUser(model.User.Value); + + var sticker = SocketCustomSticker.Create(Discord, model, this, model.User.IsSpecified ? model.User.Value.Id : null); + _stickers[model.Id] = sticker; + return sticker; + } + + internal SocketCustomSticker AddOrUpdateSticker(StickerModel model) + { + if (_stickers.TryGetValue(model.Id, out SocketCustomSticker sticker)) + _stickers[model.Id].Update(model); + else + sticker = AddSticker(model); + + return sticker; + } + + internal SocketCustomSticker RemoveSticker(ulong id) + { + if (_stickers.TryRemove(id, out SocketCustomSticker sticker)) + return sticker; + return null; + } + #endregion + + #region Users /// public Task AddGuildUserAsync(ulong id, string accessToken, Action func = null, RequestOptions options = null) => GuildHelper.AddGuildUserAsync(this, Discord, id, accessToken, func, options); @@ -935,8 +1213,118 @@ internal void CompleteDownloadUsers() /// public Task> SearchUsersAsync(string query, int limit = DiscordConfig.MaxUsersPerBatch, RequestOptions options = null) => GuildHelper.SearchUsersAsync(this, Discord, query, limit, options); + #endregion + + #region Guild Events + + /// + /// Gets an event in this guild. + /// + /// The snowflake identifier for the event. + /// + /// An event that is associated with the specified ; if none is found. + /// + public SocketGuildEvent GetEvent(ulong id) + { + if (_events.TryGetValue(id, out SocketGuildEvent value)) + return value; + return null; + } + + internal SocketGuildEvent RemoveEvent(ulong id) + { + if (_events.TryRemove(id, out SocketGuildEvent value)) + return value; + return null; + } + + internal SocketGuildEvent AddOrUpdateEvent(EventModel model) + { + if (_events.TryGetValue(model.Id, out SocketGuildEvent value)) + value.Update(model); + else + { + value = SocketGuildEvent.Create(Discord, this, model); + _events[model.Id] = value; + } + return value; + } + + /// + /// Gets an event within this guild. + /// + /// The snowflake identifier for the event. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. + /// + public Task GetEventAsync(ulong id, RequestOptions options = null) + => GuildHelper.GetGuildEventAsync(Discord, id, this, options); - //Audit logs + /// + /// Gets all active events within this guild. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. + /// + public Task> GetEventsAsync(RequestOptions options = null) + => GuildHelper.GetGuildEventsAsync(Discord, this, options); + + /// + /// Creates an event within this guild. + /// + /// The name of the event. + /// The privacy level of the event. + /// The start time of the event. + /// The type of the event. + /// The description of the event. + /// The end time of the event. + /// + /// The channel id of the event. + /// + /// The event must have a type of or + /// in order to use this property. + /// + /// + /// A collection of speakers for the event. + /// The location of the event; links are supported + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous create operation. + /// + public Task CreateEventAsync( + string name, + DateTimeOffset startTime, + GuildScheduledEventType type, + GuildScheduledEventPrivacyLevel privacyLevel = GuildScheduledEventPrivacyLevel.Private, + string description = null, + DateTimeOffset? endTime = null, + ulong? channelId = null, + string location = null, + RequestOptions options = null) + { + // requirements taken from https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-permissions-requirements + switch (type) + { + case GuildScheduledEventType.Stage: + CurrentUser.GuildPermissions.Ensure(GuildPermission.ManageEvents | GuildPermission.ManageChannels | GuildPermission.MuteMembers | GuildPermission.MoveMembers); + break; + case GuildScheduledEventType.Voice: + CurrentUser.GuildPermissions.Ensure(GuildPermission.ManageEvents | GuildPermission.ViewChannel | GuildPermission.Connect); + break; + case GuildScheduledEventType.External: + CurrentUser.GuildPermissions.Ensure(GuildPermission.ManageEvents); + break; + } + + return GuildHelper.CreateGuildEventAsync(Discord, this, name, privacyLevel, startTime, type, description, endTime, channelId, location, options); + } + + + #endregion + + #region Audit logs /// /// Gets the specified number of audit log entries for this guild. /// @@ -951,8 +1339,9 @@ public Task> SearchUsersAsync(string query, i /// public IAsyncEnumerable> GetAuditLogsAsync(int limit, RequestOptions options = null, ulong? beforeId = null, ulong? userId = null, ActionType? actionType = null) => GuildHelper.GetAuditLogsAsync(this, Discord, beforeId, limit, options, userId: userId, actionType: actionType); + #endregion - //Webhooks + #region Webhooks /// /// Gets a webhook found within this guild. /// @@ -974,8 +1363,9 @@ public Task GetWebhookAsync(ulong id, RequestOptions options = null /// public Task> GetWebhooksAsync(RequestOptions options = null) => GuildHelper.GetWebhooksAsync(this, Discord, options); + #endregion - //Emotes + #region Emotes /// public Task> GetEmotesAsync(RequestOptions options = null) => GuildHelper.GetEmotesAsync(this, Discord, options); @@ -993,7 +1383,154 @@ public Task ModifyEmoteAsync(GuildEmote emote, Action GuildHelper.DeleteEmoteAsync(this, Discord, emote.Id, options); - //Voice States + /// + /// Moves the user to the voice channel. + /// + /// The user to move. + /// the channel where the user gets moved to. + /// A task that represents the asynchronous operation for moving a user. + public Task MoveAsync(IGuildUser user, IVoiceChannel targetChannel) + => user.ModifyAsync(x => x.Channel = new Optional(targetChannel)); + + /// + /// Disconnects the user from its current voice channel + /// + /// The user to disconnect. + /// A task that represents the asynchronous operation for disconnecting a user. + async Task IGuild.DisconnectAsync(IGuildUser user) => await user.ModifyAsync(x => x.Channel = new Optional()); + #endregion + + #region Stickers + /// + /// Gets a specific sticker within this guild. + /// + /// The id of the sticker to get. + /// The that determines whether the object should be fetched from cache. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains the sticker found with the + /// specified ; if none is found. + /// + public async ValueTask GetStickerAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) + { + var sticker = _stickers.FirstOrDefault(x => x.Key == id); + + if (sticker.Value != null) + return sticker.Value; + + if (mode == CacheMode.CacheOnly) + return null; + + var model = await Discord.ApiClient.GetGuildStickerAsync(Id, id, options).ConfigureAwait(false); + + if (model == null) + return null; + + return AddOrUpdateSticker(model); + } + /// + /// Gets a specific sticker within this guild. + /// + /// The id of the sticker to get. + /// A sticker, if none is found then . + public SocketCustomSticker GetSticker(ulong id) + => GetStickerAsync(id, CacheMode.CacheOnly).GetAwaiter().GetResult(); + /// + /// Gets a collection of all stickers within this guild. + /// + /// The that determines whether the object should be fetched from cache. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous get operation. The task result contains a read-only collection + /// of stickers found within the guild. + /// + public async ValueTask> GetStickersAsync(CacheMode mode = CacheMode.AllowDownload, + RequestOptions options = null) + { + if (Stickers.Count > 0) + return Stickers; + + if (mode == CacheMode.CacheOnly) + return ImmutableArray.Create(); + + var models = await Discord.ApiClient.ListGuildStickersAsync(Id, options).ConfigureAwait(false); + + List stickers = new(); + + foreach (var model in models) + { + stickers.Add(AddOrUpdateSticker(model)); + } + + return stickers; + } + /// + /// Creates a new sticker in this guild. + /// + /// The name of the sticker. + /// The description of the sticker. + /// The tags of the sticker. + /// The image of the new emote. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the created sticker. + /// + public async Task CreateStickerAsync(string name, string description, IEnumerable tags, Image image, + RequestOptions options = null) + { + var model = await GuildHelper.CreateStickerAsync(Discord, this, name, description, tags, image, options).ConfigureAwait(false); + + return AddOrUpdateSticker(model); + } + /// + /// Creates a new sticker in this guild + /// + /// The name of the sticker. + /// The description of the sticker. + /// The tags of the sticker. + /// The path of the file to upload. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the created sticker. + /// + public Task CreateStickerAsync(string name, string description, IEnumerable tags, string path, + RequestOptions options = null) + { + var fs = File.OpenRead(path); + return CreateStickerAsync(name, description, tags, fs, Path.GetFileName(fs.Name), options); + } + /// + /// Creates a new sticker in this guild + /// + /// The name of the sticker. + /// The description of the sticker. + /// The tags of the sticker. + /// The stream containing the file data. + /// The name of the file with the extension, ex: image.png. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous creation operation. The task result contains the created sticker. + /// + public async Task CreateStickerAsync(string name, string description, IEnumerable tags, Stream stream, + string filename, RequestOptions options = null) + { + var model = await GuildHelper.CreateStickerAsync(Discord, this, name, description, tags, stream, filename, options).ConfigureAwait(false); + + return AddOrUpdateSticker(model); + } + /// + /// Deletes a sticker within this guild. + /// + /// The sticker to delete. + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous removal operation. + /// + public Task DeleteStickerAsync(SocketCustomSticker sticker, RequestOptions options = null) + => sticker.DeleteAsync(options); + #endregion + + #region Voice States internal async Task AddOrUpdateVoiceStateAsync(ClientState state, VoiceStateModel model) { var voiceChannel = state.GetChannel(model.ChannelId.Value) as SocketVoiceChannel; @@ -1037,8 +1574,9 @@ internal async Task AddOrUpdateVoiceStateAsync(ClientState sta } return null; } + #endregion - //Audio + #region Audio internal AudioInStream GetAudioStream(ulong userId) { return _audioClient?.GetInputStream(userId); @@ -1143,7 +1681,7 @@ private async Task DisconnectAudioInternalAsync() } internal async Task FinishConnectAudio(string url, string token) { - //TODO: Mem Leak: Disconnected/Connected handlers arent cleaned up + //TODO: Mem Leak: Disconnected/Connected handlers aren't cleaned up var voiceState = GetVoiceState(Discord.CurrentUser.Id).Value; await _audioLock.WaitAsync().ConfigureAwait(false); @@ -1192,8 +1730,9 @@ internal async Task RepopulateAudioStreamsAsync() public override string ToString() => Name; private string DebuggerDisplay => $"{Name} ({Id})"; internal SocketGuild Clone() => MemberwiseClone() as SocketGuild; + #endregion - //IGuild + #region IGuild /// ulong? IGuild.AFKChannelId => AFKChannelId; /// @@ -1216,7 +1755,17 @@ internal async Task RepopulateAudioStreamsAsync() int? IGuild.ApproximateMemberCount => null; /// int? IGuild.ApproximatePresenceCount => null; - + /// + IReadOnlyCollection IGuild.Stickers => Stickers; + /// + async Task IGuild.CreateEventAsync(string name, DateTimeOffset startTime, GuildScheduledEventType type, GuildScheduledEventPrivacyLevel privacyLevel, string description, DateTimeOffset? endTime, ulong? channelId, string location, RequestOptions options) + => await CreateEventAsync(name, startTime, type, privacyLevel, description, endTime, channelId, location, options).ConfigureAwait(false); + /// + async Task IGuild.GetEventAsync(ulong id, RequestOptions options) + => await GetEventAsync(id, options).ConfigureAwait(false); + /// + async Task> IGuild.GetEventsAsync(RequestOptions options) + => await GetEventsAsync(options).ConfigureAwait(false); /// async Task> IGuild.GetBansAsync(RequestOptions options) => await GetBansAsync(options).ConfigureAwait(false); @@ -1240,15 +1789,27 @@ Task> IGuild.GetTextChannelsAsync(CacheMode mo Task IGuild.GetTextChannelAsync(ulong id, CacheMode mode, RequestOptions options) => Task.FromResult(GetTextChannel(id)); /// + Task IGuild.GetThreadChannelAsync(ulong id, CacheMode mode, RequestOptions options) + => Task.FromResult(GetThreadChannel(id)); + /// + Task> IGuild.GetThreadChannelsAsync(CacheMode mode, RequestOptions options) + => Task.FromResult>(ThreadChannels); + /// Task> IGuild.GetVoiceChannelsAsync(CacheMode mode, RequestOptions options) => Task.FromResult>(VoiceChannels); /// - Task> IGuild.GetCategoriesAsync(CacheMode mode , RequestOptions options) + Task> IGuild.GetCategoriesAsync(CacheMode mode, RequestOptions options) => Task.FromResult>(CategoryChannels); /// Task IGuild.GetVoiceChannelAsync(ulong id, CacheMode mode, RequestOptions options) => Task.FromResult(GetVoiceChannel(id)); /// + Task IGuild.GetStageChannelAsync(ulong id, CacheMode mode, RequestOptions options) + => Task.FromResult(GetStageChannel(id)); + /// + Task> IGuild.GetStageChannelsAsync(CacheMode mode, RequestOptions options) + => Task.FromResult>(StageChannels); + /// Task IGuild.GetAFKChannelAsync(CacheMode mode, RequestOptions options) => Task.FromResult(AFKChannel); /// @@ -1273,6 +1834,9 @@ async Task IGuild.CreateTextChannelAsync(string name, Action IGuild.CreateVoiceChannelAsync(string name, Action func, RequestOptions options) => await CreateVoiceChannelAsync(name, func, options).ConfigureAwait(false); /// + async Task IGuild.CreateStageChannelAsync(string name, Action func, RequestOptions options) + => await CreateStageChannelAsync(name, func, options).ConfigureAwait(false); + /// async Task IGuild.CreateCategoryAsync(string name, Action func, RequestOptions options) => await CreateCategoryChannelAsync(name, func, options).ConfigureAwait(false); @@ -1350,6 +1914,37 @@ async Task IGuild.GetWebhookAsync(ulong id, RequestOptions options) /// async Task> IGuild.GetWebhooksAsync(RequestOptions options) => await GetWebhooksAsync(options).ConfigureAwait(false); + /// + async Task> IGuild.GetApplicationCommandsAsync (RequestOptions options) + => await GetApplicationCommandsAsync(options).ConfigureAwait(false); + /// + async Task IGuild.CreateStickerAsync(string name, string description, IEnumerable tags, Image image, RequestOptions options) + => await CreateStickerAsync(name, description, tags, image, options); + /// + async Task IGuild.CreateStickerAsync(string name, string description, IEnumerable tags, Stream stream, string filename, RequestOptions options) + => await CreateStickerAsync(name, description, tags, stream, filename, options); + /// + async Task IGuild.CreateStickerAsync(string name, string description, IEnumerable tags, string path, RequestOptions options) + => await CreateStickerAsync(name, description, tags, path, options); + /// + async Task IGuild.GetStickerAsync(ulong id, CacheMode mode, RequestOptions options) + => await GetStickerAsync(id, mode, options); + /// + async Task> IGuild.GetStickersAsync(CacheMode mode, RequestOptions options) + => await GetStickersAsync(mode, options); + /// + Task IGuild.DeleteStickerAsync(ICustomSticker sticker, RequestOptions options) + => DeleteStickerAsync(_stickers[sticker.Id], options); + /// + async Task IGuild.GetApplicationCommandAsync(ulong id, CacheMode mode, RequestOptions options) + => await GetApplicationCommandAsync(id, mode, options); + /// + async Task IGuild.CreateApplicationCommandAsync(ApplicationCommandProperties properties, RequestOptions options) + => await CreateApplicationCommandAsync(properties, options); + /// + async Task> IGuild.BulkOverwriteApplicationCommandsAsync(ApplicationCommandProperties[] properties, + RequestOptions options) + => await BulkOverwriteApplicationCommandAsync(properties, options); void IDisposable.Dispose() { @@ -1357,5 +1952,6 @@ void IDisposable.Dispose() _audioLock?.Dispose(); _audioClient?.Dispose(); } + #endregion } } diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuildEvent.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuildEvent.cs new file mode 100644 index 000000000..6974c0498 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuildEvent.cs @@ -0,0 +1,216 @@ +using Discord.Rest; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Model = Discord.API.GuildScheduledEvent; + +namespace Discord.WebSocket +{ + /// + /// Represents a WebSocket-based guild event. + /// + public class SocketGuildEvent : SocketEntity, IGuildScheduledEvent + { + /// + /// Gets the guild of the event. + /// + public SocketGuild Guild { get; private set; } + + /// + /// Gets the channel of the event. + /// + public SocketGuildChannel Channel { get; private set; } + + /// + /// Gets the user who created the event. + /// + public SocketGuildUser Creator { get; private set; } + + /// + public string Name { get; private set; } + + /// + public string Description { get; private set; } + + /// + public DateTimeOffset StartTime { get; private set; } + + /// + public DateTimeOffset? EndTime { get; private set; } + + /// + public GuildScheduledEventPrivacyLevel PrivacyLevel { get; private set; } + + /// + public GuildScheduledEventStatus Status { get; private set; } + + /// + public GuildScheduledEventType Type { get; private set; } + + /// + public ulong? EntityId { get; private set; } + + /// + public string Location { get; private set; } + + /// + public int? UserCount { get; private set; } + + internal SocketGuildEvent(DiscordSocketClient client, SocketGuild guild, ulong id) + : base(client, id) + { + Guild = guild; + } + + internal static SocketGuildEvent Create(DiscordSocketClient client, SocketGuild guild, Model model) + { + var entity = new SocketGuildEvent(client, guild, model.Id); + entity.Update(model); + return entity; + } + + internal void Update(Model model) + { + if (model.ChannelId.IsSpecified && model.ChannelId.Value != null) + { + Channel = Guild.GetChannel(model.ChannelId.Value.Value); + } + + if (model.CreatorId.IsSpecified) + { + var guildUser = Guild.GetUser(model.CreatorId.Value); + + if(guildUser != null) + { + if(model.Creator.IsSpecified) + guildUser.Update(Discord.State, model.Creator.Value); + + Creator = guildUser; + } + else if (guildUser == null && model.Creator.IsSpecified) + { + guildUser = SocketGuildUser.Create(Guild, Discord.State, model.Creator.Value); + Creator = guildUser; + } + } + + Name = model.Name; + Description = model.Description.GetValueOrDefault(); + + EntityId = model.EntityId; + Location = model.EntityMetadata?.Location.GetValueOrDefault(); + Type = model.EntityType; + + PrivacyLevel = model.PrivacyLevel; + EndTime = model.ScheduledEndTime; + StartTime = model.ScheduledStartTime; + Status = model.Status; + UserCount = model.UserCount.ToNullable(); + } + + /// + public Task DeleteAsync(RequestOptions options = null) + => GuildHelper.DeleteEventAsync(Discord, this, options); + + /// + public Task StartAsync(RequestOptions options = null) + => ModifyAsync(x => x.Status = GuildScheduledEventStatus.Active); + + /// + public Task EndAsync(RequestOptions options = null) + => ModifyAsync(x => x.Status = Status == GuildScheduledEventStatus.Scheduled + ? GuildScheduledEventStatus.Cancelled + : GuildScheduledEventStatus.Completed); + + /// + public async Task ModifyAsync(Action func, RequestOptions options = null) + { + var model = await GuildHelper.ModifyGuildEventAsync(Discord, func, this, options).ConfigureAwait(false); + Update(model); + } + + /// + /// Gets a collection of users that are interested in this event. + /// + /// The amount of users to fetch. + /// The options to be used when sending the request. + /// + /// A read-only collection of users. + /// + public Task> GetUsersAsync(int limit = 100, RequestOptions options = null) + => GuildHelper.GetEventUsersAsync(Discord, this, limit, options); + + /// + /// Gets a collection of N users interested in the event. + /// + /// + /// + /// The returned collection is an asynchronous enumerable object; one must call + /// to access the individual messages as a + /// collection. + /// + /// This method will attempt to fetch all users that are interested in the event. + /// The library will attempt to split up the requests according to and . + /// In other words, if there are 300 users, and the constant + /// is 100, the request will be split into 3 individual requests; thus returning 3 individual asynchronous + /// responses, hence the need of flattening. + /// + /// The options to be used when sending the request. + /// + /// Paged collection of users. + /// + public IAsyncEnumerable> GetUsersAsync(RequestOptions options = null) + => GuildHelper.GetEventUsersAsync(Discord, this, null, null, options); + + /// + /// Gets a collection of N users interested in the event. + /// + /// + /// + /// The returned collection is an asynchronous enumerable object; one must call + /// to access the individual users as a + /// collection. + /// + /// + /// Do not fetch too many users at once! This may cause unwanted preemptive rate limit or even actual + /// rate limit, causing your bot to freeze! + /// + /// This method will attempt to fetch the number of users specified under around + /// the user depending on the . The library will + /// attempt to split up the requests according to your and + /// . In other words, should the user request 500 users, + /// and the constant is 100, the request will + /// be split into 5 individual requests; thus returning 5 individual asynchronous responses, hence the need + /// of flattening. + /// + /// The ID of the starting user to get the users from. + /// The direction of the users to be gotten from. + /// The numbers of users to be gotten from. + /// The options to be used when sending the request. + /// + /// Paged collection of users. + /// + public IAsyncEnumerable> GetUsersAsync(ulong fromUserId, Direction dir, int limit = DiscordConfig.MaxGuildEventUsersPerBatch, RequestOptions options = null) + => GuildHelper.GetEventUsersAsync(Discord, this, fromUserId, dir, limit, options); + + #region IGuildScheduledEvent + + /// + IAsyncEnumerable> IGuildScheduledEvent.GetUsersAsync(RequestOptions options) + => GetUsersAsync(options); + /// + IAsyncEnumerable> IGuildScheduledEvent.GetUsersAsync(ulong fromUserId, Direction dir, int limit, RequestOptions options) + => GetUsersAsync(fromUserId, dir, limit, options); + /// + IGuild IGuildScheduledEvent.Guild => Guild; + /// + IUser IGuildScheduledEvent.Creator => Creator; + /// + ulong? IGuildScheduledEvent.ChannelId => Channel?.Id; + + #endregion + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/ContextMenuCommands/MessageCommands/SocketMessageCommand.cs b/src/Discord.Net.WebSocket/Entities/Interaction/ContextMenuCommands/MessageCommands/SocketMessageCommand.cs new file mode 100644 index 000000000..0aa061439 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/ContextMenuCommands/MessageCommands/SocketMessageCommand.cs @@ -0,0 +1,45 @@ +using DataModel = Discord.API.ApplicationCommandInteractionData; +using Model = Discord.API.Interaction; + +namespace Discord.WebSocket +{ + /// + /// Represents a Websocket-based slash command received over the gateway. + /// + public class SocketMessageCommand : SocketCommandBase, IMessageCommandInteraction, IDiscordInteraction + { + /// + /// The data associated with this interaction. + /// + public new SocketMessageCommandData Data { get; } + + internal SocketMessageCommand(DiscordSocketClient client, Model model, ISocketMessageChannel channel) + : base(client, model, channel) + { + var dataModel = model.Data.IsSpecified + ? (DataModel)model.Data.Value + : null; + + ulong? guildId = null; + if (Channel is SocketGuildChannel guildChannel) + guildId = guildChannel.Guild.Id; + + Data = SocketMessageCommandData.Create(client, dataModel, model.Id, guildId); + } + + internal new static SocketInteraction Create(DiscordSocketClient client, Model model, ISocketMessageChannel channel) + { + var entity = new SocketMessageCommand(client, model, channel); + entity.Update(model); + return entity; + } + + //IMessageCommandInteraction + /// + IMessageCommandInteractionData IMessageCommandInteraction.Data => Data; + + //IDiscordInteraction + /// + IDiscordInteractionData IDiscordInteraction.Data => Data; + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/ContextMenuCommands/MessageCommands/SocketMessageCommandData.cs b/src/Discord.Net.WebSocket/Entities/Interaction/ContextMenuCommands/MessageCommands/SocketMessageCommandData.cs new file mode 100644 index 000000000..71a30b44a --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/ContextMenuCommands/MessageCommands/SocketMessageCommandData.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.Linq; +using Model = Discord.API.ApplicationCommandInteractionData; + +namespace Discord.WebSocket +{ + /// + /// Represents the data tied with the interaction. + /// + public class SocketMessageCommandData : SocketCommandBaseData, IMessageCommandInteractionData, IDiscordInteractionData + { + /// + /// Gets the message associated with this message command. + /// + public SocketMessage Message + => ResolvableData?.Messages.FirstOrDefault().Value; + + /// + /// + /// Note Not implemented for + /// + public override IReadOnlyCollection Options + => throw new System.NotImplementedException(); + + internal SocketMessageCommandData(DiscordSocketClient client, Model model, ulong? guildId) + : base(client, model, guildId) { } + + internal new static SocketMessageCommandData Create(DiscordSocketClient client, Model model, ulong id, ulong? guildId) + { + var entity = new SocketMessageCommandData(client, model, guildId); + entity.Update(model); + return entity; + } + + //IMessageCommandInteractionData + /// + IMessage IMessageCommandInteractionData.Message => Message; + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/ContextMenuCommands/UserCommands/SocketUserCommand.cs b/src/Discord.Net.WebSocket/Entities/Interaction/ContextMenuCommands/UserCommands/SocketUserCommand.cs new file mode 100644 index 000000000..40ee5b537 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/ContextMenuCommands/UserCommands/SocketUserCommand.cs @@ -0,0 +1,45 @@ +using DataModel = Discord.API.ApplicationCommandInteractionData; +using Model = Discord.API.Interaction; + +namespace Discord.WebSocket +{ + /// + /// Represents a Websocket-based slash command received over the gateway. + /// + public class SocketUserCommand : SocketCommandBase, IUserCommandInteraction, IDiscordInteraction + { + /// + /// The data associated with this interaction. + /// + public new SocketUserCommandData Data { get; } + + internal SocketUserCommand(DiscordSocketClient client, Model model, ISocketMessageChannel channel) + : base(client, model, channel) + { + var dataModel = model.Data.IsSpecified + ? (DataModel)model.Data.Value + : null; + + ulong? guildId = null; + if (Channel is SocketGuildChannel guildChannel) + guildId = guildChannel.Guild.Id; + + Data = SocketUserCommandData.Create(client, dataModel, model.Id, guildId); + } + + internal new static SocketInteraction Create(DiscordSocketClient client, Model model, ISocketMessageChannel channel) + { + var entity = new SocketUserCommand(client, model, channel); + entity.Update(model); + return entity; + } + + //IUserCommandInteraction + /// + IUserCommandInteractionData IUserCommandInteraction.Data => Data; + + //IDiscordInteraction + /// + IDiscordInteractionData IDiscordInteraction.Data => Data; + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/ContextMenuCommands/UserCommands/SocketUserCommandData.cs b/src/Discord.Net.WebSocket/Entities/Interaction/ContextMenuCommands/UserCommands/SocketUserCommandData.cs new file mode 100644 index 000000000..eaebbcb06 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/ContextMenuCommands/UserCommands/SocketUserCommandData.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.Linq; +using Model = Discord.API.ApplicationCommandInteractionData; + +namespace Discord.WebSocket +{ + /// + /// Represents the data tied with the interaction. + /// + public class SocketUserCommandData : SocketCommandBaseData, IUserCommandInteractionData, IDiscordInteractionData + { + /// + /// Gets the user who this command targets. + /// + public SocketUser Member + => (SocketUser)ResolvableData.GuildMembers.Values.FirstOrDefault() ?? ResolvableData.Users.Values.FirstOrDefault(); + + /// + /// + /// Note Not implemented for + /// + public override IReadOnlyCollection Options + => throw new System.NotImplementedException(); + + internal SocketUserCommandData(DiscordSocketClient client, Model model, ulong? guildId) + : base(client, model, guildId) { } + + internal new static SocketUserCommandData Create(DiscordSocketClient client, Model model, ulong id, ulong? guildId) + { + var entity = new SocketUserCommandData(client, model, guildId); + entity.Update(model); + return entity; + } + + //IUserCommandInteractionData + /// + IUser IUserCommandInteractionData.User => Member; + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/MessageComponents/SocketMessageComponent.cs b/src/Discord.Net.WebSocket/Entities/Interaction/MessageComponents/SocketMessageComponent.cs new file mode 100644 index 000000000..928a4302a --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/MessageComponents/SocketMessageComponent.cs @@ -0,0 +1,436 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Model = Discord.API.Interaction; +using DataModel = Discord.API.MessageComponentInteractionData; +using Discord.Rest; +using System.Collections.Generic; +using Discord.Net.Rest; +using System.IO; + +namespace Discord.WebSocket +{ + /// + /// Represents a Websocket-based interaction type for Message Components. + /// + public class SocketMessageComponent : SocketInteraction, IComponentInteraction, IDiscordInteraction + { + /// + /// Gets the data received with this interaction, contains the button that was clicked. + /// + public new SocketMessageComponentData Data { get; } + + /// + /// Gets the message that contained the trigger for this interaction. + /// + public SocketUserMessage Message { get; private set; } + + private object _lock = new object(); + public override bool HasResponded { get; internal set; } = false; + + internal SocketMessageComponent(DiscordSocketClient client, Model model, ISocketMessageChannel channel) + : base(client, model.Id, channel) + { + var dataModel = model.Data.IsSpecified + ? (DataModel)model.Data.Value + : null; + + Data = new SocketMessageComponentData(dataModel); + } + + internal new static SocketMessageComponent Create(DiscordSocketClient client, Model model, ISocketMessageChannel channel) + { + var entity = new SocketMessageComponent(client, model, channel); + entity.Update(model); + return entity; + } + internal override void Update(Model model) + { + base.Update(model); + + if (model.Message.IsSpecified) + { + if (Message == null) + { + SocketUser author = null; + if (Channel is SocketGuildChannel channel) + { + if (model.Message.Value.WebhookId.IsSpecified) + author = SocketWebhookUser.Create(channel.Guild, Discord.State, model.Message.Value.Author.Value, model.Message.Value.WebhookId.Value); + else if (model.Message.Value.Author.IsSpecified) + author = channel.Guild.GetUser(model.Message.Value.Author.Value.Id); + } + else if (model.Message.Value.Author.IsSpecified) + author = (Channel as SocketChannel).GetUser(model.Message.Value.Author.Value.Id); + + Message = SocketUserMessage.Create(Discord, Discord.State, author, Channel, model.Message.Value); + } + else + { + Message.Update(Discord.State, model.Message.Value); + } + } + } + /// + public override async Task RespondAsync( + string text = null, + Embed[] embeds = null, + bool isTTS = false, + bool ephemeral = false, + AllowedMentions allowedMentions = null, + RequestOptions options = null, + MessageComponent component = null, + Embed embed = null) + { + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + if (!InteractionHelper.CanSendResponse(this)) + throw new TimeoutException($"Cannot respond to an interaction after {InteractionHelper.ResponseTimeLimit} seconds!"); + + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + + // check that user flag and user Id list are exclusive, same with role flag and role Id list + if (allowedMentions != null && allowedMentions.AllowedTypes.HasValue) + { + if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Users) && + allowedMentions.UserIds != null && allowedMentions.UserIds.Count > 0) + { + throw new ArgumentException("The Users flag is mutually exclusive with the list of User Ids.", nameof(allowedMentions)); + } + + if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Roles) && + allowedMentions.RoleIds != null && allowedMentions.RoleIds.Count > 0) + { + throw new ArgumentException("The Roles flag is mutually exclusive with the list of Role Ids.", nameof(allowedMentions)); + } + } + + var response = new API.InteractionResponse + { + Type = InteractionResponseType.ChannelMessageWithSource, + Data = new API.InteractionCallbackData + { + Content = text ?? Optional.Unspecified, + AllowedMentions = allowedMentions?.ToModel(), + Embeds = embeds.Select(x => x.ToModel()).ToArray(), + TTS = isTTS, + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified + } + }; + + if (ephemeral) + response.Data.Value.Flags = MessageFlags.Ephemeral; + + lock (_lock) + { + if (HasResponded) + { + throw new InvalidOperationException("Cannot respond, update, or defer twice to the same interaction"); + } + } + + await InteractionHelper.SendInteractionResponseAsync(Discord, response, Id, Token, options).ConfigureAwait(false); + + lock (_lock) + { + HasResponded = true; + } + } + + /// + /// Updates the message which this component resides in with the type + /// + /// A delegate containing the properties to modify the message with. + /// The request options for this request. + /// A task that represents the asynchronous operation of updating the message. + public async Task UpdateAsync(Action func, RequestOptions options = null) + { + var args = new MessageProperties(); + func(args); + + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + if (!InteractionHelper.CanSendResponse(this)) + throw new TimeoutException($"Cannot respond to an interaction after {InteractionHelper.ResponseTimeLimit} seconds!"); + + if (args.AllowedMentions.IsSpecified) + { + var allowedMentions = args.AllowedMentions.Value; + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions), "A max of 100 user Ids are allowed."); + } + + var embed = args.Embed; + var embeds = args.Embeds; + + bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : !string.IsNullOrEmpty(Message.Content); + bool hasEmbeds = embed.IsSpecified && embed.Value != null || embeds.IsSpecified && embeds.Value?.Length > 0 || Message.Embeds.Any(); + + if (!hasText && !hasEmbeds) + Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content)); + + var apiEmbeds = embed.IsSpecified || embeds.IsSpecified ? new List() : null; + + if (embed.IsSpecified && embed.Value != null) + { + apiEmbeds.Add(embed.Value.ToModel()); + } + + if (embeds.IsSpecified && embeds.Value != null) + { + apiEmbeds.AddRange(embeds.Value.Select(x => x.ToModel())); + } + + Preconditions.AtMost(apiEmbeds?.Count ?? 0, 10, nameof(args.Embeds), "A max of 10 embeds are allowed."); + + // check that user flag and user Id list are exclusive, same with role flag and role Id list + if (args.AllowedMentions.IsSpecified && args.AllowedMentions.Value != null && args.AllowedMentions.Value.AllowedTypes.HasValue) + { + var allowedMentions = args.AllowedMentions.Value; + if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Users) + && allowedMentions.UserIds != null && allowedMentions.UserIds.Count > 0) + { + throw new ArgumentException("The Users flag is mutually exclusive with the list of User Ids.", nameof(args.AllowedMentions)); + } + + if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Roles) + && allowedMentions.RoleIds != null && allowedMentions.RoleIds.Count > 0) + { + throw new ArgumentException("The Roles flag is mutually exclusive with the list of Role Ids.", nameof(args.AllowedMentions)); + } + } + + var response = new API.InteractionResponse + { + Type = InteractionResponseType.UpdateMessage, + Data = new API.InteractionCallbackData + { + Content = args.Content, + AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value?.ToModel() : Optional.Unspecified, + Embeds = apiEmbeds?.ToArray() ?? Optional.Unspecified, + Components = args.Components.IsSpecified + ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Array.Empty() + : Optional.Unspecified, + Flags = args.Flags.IsSpecified ? args.Flags.Value ?? Optional.Unspecified : Optional.Unspecified + } + }; + + lock (_lock) + { + if (HasResponded) + { + throw new InvalidOperationException("Cannot respond, update, or defer twice to the same interaction"); + } + } + + await InteractionHelper.SendInteractionResponseAsync(Discord, response, Id, Token, options).ConfigureAwait(false); + + lock (_lock) + { + HasResponded = true; + } + } + + /// + public override async Task FollowupAsync( + string text = null, + Embed[] embeds = null, + bool isTTS = false, + bool ephemeral = false, + AllowedMentions allowedMentions = null, + RequestOptions options = null, + MessageComponent component = null, + Embed embed = null) + { + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + + var args = new API.Rest.CreateWebhookMessageParams + { + Content = text, + AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, + IsTTS = isTTS, + Embeds = embeds.Select(x => x.ToModel()).ToArray(), + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified + }; + + if (ephemeral) + args.Flags = MessageFlags.Ephemeral; + + return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options).ConfigureAwait(false); + } + + /// + public override async Task FollowupWithFileAsync( + Stream fileStream, + string fileName, + string text = null, + Embed[] embeds = null, + bool isTTS = false, + bool ephemeral = false, + AllowedMentions allowedMentions = null, + RequestOptions options = null, + MessageComponent component = null, + Embed embed = null) + { + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + Preconditions.NotNull(fileStream, nameof(fileStream), "File Stream must have data"); + Preconditions.NotNullOrWhitespace(fileName, nameof(fileName), "File Name must not be empty or null"); + + var args = new API.Rest.CreateWebhookMessageParams + { + Content = text, + AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, + IsTTS = isTTS, + Embeds = embeds.Select(x => x.ToModel()).ToArray(), + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified, + File = fileStream is not null ? new MultipartFile(fileStream, fileName) : Optional.Unspecified + }; + + if (ephemeral) + args.Flags = MessageFlags.Ephemeral; + + return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options).ConfigureAwait(false); + } + + /// + public override async Task FollowupWithFileAsync( + string filePath, + string text = null, + string fileName = null, + Embed[] embeds = null, + bool isTTS = false, + bool ephemeral = false, + AllowedMentions allowedMentions = null, + RequestOptions options = null, + MessageComponent component = null, + Embed embed = null) + { + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + Preconditions.NotNullOrWhitespace(filePath, nameof(filePath), "Path must exist"); + + var args = new API.Rest.CreateWebhookMessageParams + { + Content = text, + AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, + IsTTS = isTTS, + Embeds = embeds.Select(x => x.ToModel()).ToArray(), + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified, + File = !string.IsNullOrEmpty(filePath) ? new MultipartFile(new MemoryStream(File.ReadAllBytes(filePath), false), fileName) : Optional.Unspecified + }; + + if (ephemeral) + args.Flags = MessageFlags.Ephemeral; + + return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options).ConfigureAwait(false); + } + + /// + /// Defers an interaction and responds with type 5 () + /// + /// to send this message ephemerally, otherwise . + /// The request options for this request. + /// + /// A task that represents the asynchronous operation of acknowledging the interaction. + /// + public async Task DeferLoadingAsync(bool ephemeral = false, RequestOptions options = null) + { + if (!InteractionHelper.CanSendResponse(this)) + throw new TimeoutException($"Cannot defer an interaction after {InteractionHelper.ResponseTimeLimit} seconds of no response/acknowledgement"); + + var response = new API.InteractionResponse + { + Type = InteractionResponseType.DeferredChannelMessageWithSource, + Data = ephemeral ? new API.InteractionCallbackData { Flags = MessageFlags.Ephemeral } : Optional.Unspecified + }; + + lock (_lock) + { + if (HasResponded) + { + throw new InvalidOperationException("Cannot respond or defer twice to the same interaction"); + } + } + + await Discord.Rest.ApiClient.CreateInteractionResponseAsync(response, Id, Token, options).ConfigureAwait(false); + + lock (_lock) + { + HasResponded = true; + } + } + + /// + public override async Task DeferAsync(bool ephemeral = false, RequestOptions options = null) + { + if (!InteractionHelper.CanSendResponse(this)) + throw new TimeoutException($"Cannot defer an interaction after {InteractionHelper.ResponseTimeLimit} seconds of no response/acknowledgement"); + + var response = new API.InteractionResponse + { + Type = InteractionResponseType.DeferredUpdateMessage, + Data = ephemeral ? new API.InteractionCallbackData { Flags = MessageFlags.Ephemeral } : Optional.Unspecified + }; + + lock (_lock) + { + if (HasResponded) + { + throw new InvalidOperationException("Cannot respond or defer twice to the same interaction"); + } + } + + await Discord.Rest.ApiClient.CreateInteractionResponseAsync(response, Id, Token, options).ConfigureAwait(false); + + lock (_lock) + { + HasResponded = true; + } + } + + //IComponentInteraction + /// + IComponentInteractionData IComponentInteraction.Data => Data; + + /// + IUserMessage IComponentInteraction.Message => Message; + + //IDiscordInteraction + /// + IDiscordInteractionData IDiscordInteraction.Data => Data; + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/MessageComponents/SocketMessageComponentData.cs b/src/Discord.Net.WebSocket/Entities/Interaction/MessageComponents/SocketMessageComponentData.cs new file mode 100644 index 000000000..71e1d0395 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/MessageComponents/SocketMessageComponentData.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using Model = Discord.API.MessageComponentInteractionData; + +namespace Discord.WebSocket +{ + /// + /// Represents the data sent with a . + /// + public class SocketMessageComponentData : IComponentInteractionData + { + /// + /// Gets the components Custom Id that was clicked. + /// + public string CustomId { get; } + + /// + /// Gets the type of the component clicked. + /// + public ComponentType Type { get; } + + /// + /// Gets the value(s) of a interaction response. + /// + public IReadOnlyCollection Values { get; } + + internal SocketMessageComponentData(Model model) + { + CustomId = model.CustomId; + Type = model.ComponentType; + Values = model.Values.GetValueOrDefault(); + } + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketAutocompleteInteraction.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketAutocompleteInteraction.cs new file mode 100644 index 000000000..5637cb6f0 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketAutocompleteInteraction.cs @@ -0,0 +1,126 @@ +using Discord.Rest; +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Model = Discord.API.Interaction; +using DataModel = Discord.API.AutocompleteInteractionData; + +namespace Discord.WebSocket +{ + /// + /// Represents a received over the gateway. + /// + public class SocketAutocompleteInteraction : SocketInteraction, IAutocompleteInteraction, IDiscordInteraction + { + /// + /// The autocomplete data of this interaction. + /// + public new SocketAutocompleteInteractionData Data { get; } + + public override bool HasResponded { get; internal set; } + private object _lock = new object(); + + internal SocketAutocompleteInteraction(DiscordSocketClient client, Model model, ISocketMessageChannel channel) + : base(client, model.Id, channel) + { + var dataModel = model.Data.IsSpecified + ? (DataModel)model.Data.Value + : null; + + if (dataModel != null) + Data = new SocketAutocompleteInteractionData(dataModel); + } + + internal new static SocketAutocompleteInteraction Create(DiscordSocketClient client, Model model, ISocketMessageChannel channel) + { + var entity = new SocketAutocompleteInteraction(client, model, channel); + entity.Update(model); + return entity; + } + + /// + /// Responds to this interaction with a set of choices. + /// + /// + /// The set of choices for the user to pick from. + /// + /// A max of 20 choices are allowed. Passing for this argument will show the executing user that + /// there is no choices for their autocompleted input. + /// + /// + /// The request options for this response. + /// + /// A task that represents the asynchronous operation of responding to this interaction. + /// + public async Task RespondAsync(IEnumerable result, RequestOptions options = null) + { + if (!InteractionHelper.CanSendResponse(this)) + throw new TimeoutException($"Cannot respond to an interaction after {InteractionHelper.ResponseTimeLimit} seconds!"); + + lock (_lock) + { + if (HasResponded) + { + throw new InvalidOperationException("Cannot respond twice to the same interaction"); + } + } + + await InteractionHelper.SendAutocompleteResultAsync(Discord, result, Id, Token, options).ConfigureAwait(false); + lock (_lock) + { + HasResponded = true; + } + } + + /// + /// Responds to this interaction with a set of choices. + /// + /// The request options for this response. + /// + /// The set of choices for the user to pick from. + /// + /// A max of 20 choices are allowed. Passing for this argument will show the executing user that + /// there is no choices for their autocompleted input. + /// + /// + /// + /// A task that represents the asynchronous operation of responding to this interaction. + /// + public Task RespondAsync(RequestOptions options = null, params AutocompleteResult[] result) + => RespondAsync(result, options); + + /// + [Obsolete("Autocomplete interactions cannot be deferred!", true)] + public override Task DeferAsync(bool ephemeral = false, RequestOptions options = null) + => throw new NotSupportedException("Autocomplete interactions cannot be deferred!"); + + /// + [Obsolete("Autocomplete interactions cannot have followups!", true)] + public override Task FollowupAsync(string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null) + => throw new NotSupportedException("Autocomplete interactions cannot be deferred!"); + + /// + [Obsolete("Autocomplete interactions cannot have followups!", true)] + public override Task FollowupWithFileAsync(Stream fileStream, string fileName, string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null) + => throw new NotSupportedException("Autocomplete interactions cannot be deferred!"); + + /// + [Obsolete("Autocomplete interactions cannot have followups!", true)] + public override Task FollowupWithFileAsync(string filePath, string text = null, string fileName = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null) + => throw new NotSupportedException("Autocomplete interactions cannot be deferred!"); + + /// + [Obsolete("Autocomplete interactions cannot have normal responses!", true)] + public override Task RespondAsync(string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null) + => throw new NotSupportedException("Autocomplete interactions cannot be deferred!"); + + //IAutocompleteInteraction + /// + IAutocompleteInteractionData IAutocompleteInteraction.Data => Data; + + //IDiscordInteraction + /// + IDiscordInteractionData IDiscordInteraction.Data => Data; + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketAutocompleteInteractionData.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketAutocompleteInteractionData.cs new file mode 100644 index 000000000..1d9803c02 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketAutocompleteInteractionData.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using DataModel = Discord.API.AutocompleteInteractionData; + +namespace Discord.WebSocket +{ + /// + /// Represents data for a slash commands autocomplete interaction. + /// + public class SocketAutocompleteInteractionData : IAutocompleteInteractionData, IDiscordInteractionData + { + /// + /// Gets the name of the invoked command. + /// + public string CommandName { get; } + + /// + /// Gets the id of the invoked command. + /// + public ulong CommandId { get; } + + /// + /// Gets the type of the invoked command. + /// + public ApplicationCommandType Type { get; } + + /// + /// Gets the version of the invoked command. + /// + public ulong Version { get; } + + /// + /// Gets the current autocomplete option that is actively being filled out. + /// + public AutocompleteOption Current { get; } + + /// + /// Gets a collection of all the other options the executing users has filled out. + /// + public IReadOnlyCollection Options { get; } + + internal SocketAutocompleteInteractionData(DataModel model) + { + var options = model.Options.SelectMany(GetOptions); + + Current = options.FirstOrDefault(x => x.Focused); + Options = options.ToImmutableArray(); + + if (Options.Count == 1 && Current == null) + Current = Options.FirstOrDefault(); + + CommandName = model.Name; + CommandId = model.Id; + Type = model.Type; + Version = model.Version; + } + + private List GetOptions(API.AutocompleteInteractionDataOption model) + { + var options = new List(); + + options.Add(new AutocompleteOption(model.Type, model.Name, model.Value.GetValueOrDefault(null), model.Focused.GetValueOrDefault(false))); + + if (model.Options.IsSpecified) + { + options.AddRange(model.Options.Value.SelectMany(GetOptions)); + } + + return options; + } + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketSlashCommand.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketSlashCommand.cs new file mode 100644 index 000000000..5343bb225 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketSlashCommand.cs @@ -0,0 +1,45 @@ +using DataModel = Discord.API.ApplicationCommandInteractionData; +using Model = Discord.API.Interaction; + +namespace Discord.WebSocket +{ + /// + /// Represents a Websocket-based slash command received over the gateway. + /// + public class SocketSlashCommand : SocketCommandBase, ISlashCommandInteraction, IDiscordInteraction + { + /// + /// The data associated with this interaction. + /// + public new SocketSlashCommandData Data { get; } + + internal SocketSlashCommand(DiscordSocketClient client, Model model, ISocketMessageChannel channel) + : base(client, model, channel) + { + var dataModel = model.Data.IsSpecified + ? (DataModel)model.Data.Value + : null; + + ulong? guildId = null; + if (Channel is SocketGuildChannel guildChannel) + guildId = guildChannel.Guild.Id; + + Data = SocketSlashCommandData.Create(client, dataModel, guildId); + } + + internal new static SocketInteraction Create(DiscordSocketClient client, Model model, ISocketMessageChannel channel) + { + var entity = new SocketSlashCommand(client, model, channel); + entity.Update(model); + return entity; + } + + //ISlashCommandInteraction + /// + IApplicationCommandInteractionData ISlashCommandInteraction.Data => Data; + + //IDiscordInteraction + /// + IDiscordInteractionData IDiscordInteraction.Data => Data; + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketSlashCommandData.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketSlashCommandData.cs new file mode 100644 index 000000000..c385ce825 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketSlashCommandData.cs @@ -0,0 +1,30 @@ +using System.Collections.Immutable; +using System.Linq; +using Model = Discord.API.ApplicationCommandInteractionData; + +namespace Discord.WebSocket +{ + /// + /// Represents the data tied with the interaction. + /// + public class SocketSlashCommandData : SocketCommandBaseData, IDiscordInteractionData + { + internal SocketSlashCommandData(DiscordSocketClient client, Model model, ulong? guildId) + : base(client, model, guildId) { } + + internal static SocketSlashCommandData Create(DiscordSocketClient client, Model model, ulong? guildId) + { + var entity = new SocketSlashCommandData(client, model, guildId); + entity.Update(model); + return entity; + } + internal override void Update(Model model) + { + base.Update(model); + + Options = model.Options.IsSpecified + ? model.Options.Value.Select(x => new SocketSlashCommandDataOption(this, x)).ToImmutableArray() + : ImmutableArray.Create(); + } + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketSlashCommandDataOption.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketSlashCommandDataOption.cs new file mode 100644 index 000000000..265eda75b --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SlashCommands/SocketSlashCommandDataOption.cs @@ -0,0 +1,135 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Model = Discord.API.ApplicationCommandInteractionDataOption; + +namespace Discord.WebSocket +{ + /// + /// Represents a Websocket-based received by the gateway. + /// + public class SocketSlashCommandDataOption : IApplicationCommandInteractionDataOption + { + #region SocketSlashCommandDataOption + /// + public string Name { get; private set; } + + /// + public object Value { get; private set; } + + /// + public ApplicationCommandOptionType Type { get; private set; } + + /// + /// The sub command options received for this sub command group. + /// + public IReadOnlyCollection Options { get; private set; } + + internal SocketSlashCommandDataOption() { } + internal SocketSlashCommandDataOption(SocketSlashCommandData data, Model model) + { + Name = model.Name; + Type = model.Type; + + if (model.Value.IsSpecified) + { + switch (Type) + { + case ApplicationCommandOptionType.User: + case ApplicationCommandOptionType.Role: + case ApplicationCommandOptionType.Channel: + case ApplicationCommandOptionType.Mentionable: + if (ulong.TryParse($"{model.Value.Value}", out var valueId)) + { + switch (Type) + { + case ApplicationCommandOptionType.User: + { + var guildUser = data.ResolvableData.GuildMembers.FirstOrDefault(x => x.Key == valueId).Value; + + if (guildUser != null) + Value = guildUser; + else + Value = data.ResolvableData.Users.FirstOrDefault(x => x.Key == valueId).Value; + } + break; + case ApplicationCommandOptionType.Channel: + Value = data.ResolvableData.Channels.FirstOrDefault(x => x.Key == valueId).Value; + break; + case ApplicationCommandOptionType.Role: + Value = data.ResolvableData.Roles.FirstOrDefault(x => x.Key == valueId).Value; + break; + case ApplicationCommandOptionType.Mentionable: + { + if (data.ResolvableData.GuildMembers.Any(x => x.Key == valueId) || data.ResolvableData.Users.Any(x => x.Key == valueId)) + { + var guildUser = data.ResolvableData.GuildMembers.FirstOrDefault(x => x.Key == valueId).Value; + + if (guildUser != null) + Value = guildUser; + else + Value = data.ResolvableData.Users.FirstOrDefault(x => x.Key == valueId).Value; + } + else if (data.ResolvableData.Roles.Any(x => x.Key == valueId)) + { + Value = data.ResolvableData.Roles.FirstOrDefault(x => x.Key == valueId).Value; + } + } + break; + default: + Value = model.Value.Value; + break; + } + } + break; + case ApplicationCommandOptionType.String: + Value = model.Value.ToString(); + break; + case ApplicationCommandOptionType.Integer: + { + if (model.Value.Value is long val) + Value = val; + else if (long.TryParse(model.Value.Value.ToString(), out long res)) + Value = res; + } + break; + case ApplicationCommandOptionType.Boolean: + { + if (model.Value.Value is bool val) + Value = val; + else if (bool.TryParse(model.Value.Value.ToString(), out bool res)) + Value = res; + } + break; + case ApplicationCommandOptionType.Number: + { + if (model.Value.Value is int val) + Value = val; + else if (double.TryParse(model.Value.Value.ToString(), out double res)) + Value = res; + } + break; + } + } + + Options = model.Options.IsSpecified + ? model.Options.Value.Select(x => new SocketSlashCommandDataOption(data, x)).ToImmutableArray() + : ImmutableArray.Create(); + } + #endregion + + #region Converters + public static explicit operator bool(SocketSlashCommandDataOption option) + => (bool)option.Value; + public static explicit operator int(SocketSlashCommandDataOption option) + => (int)option.Value; + public static explicit operator string(SocketSlashCommandDataOption option) + => option.Value.ToString(); + #endregion + + #region IApplicationCommandInteractionDataOption + IReadOnlyCollection IApplicationCommandInteractionDataOption.Options + => Options; + #endregion + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommand.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommand.cs new file mode 100644 index 000000000..d986a93f3 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommand.cs @@ -0,0 +1,116 @@ +using Discord.Rest; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using GatewayModel = Discord.API.Gateway.ApplicationCommandCreatedUpdatedEvent; +using Model = Discord.API.ApplicationCommand; + +namespace Discord.WebSocket +{ + /// + /// Represents a Websocket-based . + /// + public class SocketApplicationCommand : SocketEntity, IApplicationCommand + { + #region SocketApplicationCommand + /// + /// if this command is a global command, otherwise . + /// + public bool IsGlobalCommand + => Guild == null; + + /// + public ulong ApplicationId { get; private set; } + + /// + public string Name { get; private set; } + + /// + public ApplicationCommandType Type { get; private set; } + + /// + public string Description { get; private set; } + + /// + public bool IsDefaultPermission { get; private set; } + + /// + /// A collection of 's for this command. + /// + /// + /// If the is not a slash command, this field will be an empty collection. + /// + public IReadOnlyCollection Options { get; private set; } + + /// + public DateTimeOffset CreatedAt + => SnowflakeUtils.FromSnowflake(Id); + + /// + /// Returns the guild this command resides in, if this command is a global command then it will return + /// + public SocketGuild Guild + => GuildId.HasValue ? Discord.GetGuild(GuildId.Value) : null; + + private ulong? GuildId { get; set; } + + internal SocketApplicationCommand(DiscordSocketClient client, ulong id, ulong? guildId) + : base(client, id) + { + GuildId = guildId; + } + internal static SocketApplicationCommand Create(DiscordSocketClient client, GatewayModel model) + { + var entity = new SocketApplicationCommand(client, model.Id, model.GuildId.ToNullable()); + entity.Update(model); + return entity; + } + + internal static SocketApplicationCommand Create(DiscordSocketClient client, Model model, ulong? guildId = null) + { + var entity = new SocketApplicationCommand(client, model.Id, guildId); + entity.Update(model); + return entity; + } + + internal void Update(Model model) + { + ApplicationId = model.ApplicationId; + Description = model.Description; + Name = model.Name; + IsDefaultPermission = model.DefaultPermissions.GetValueOrDefault(true); + Type = model.Type; + + Options = model.Options.IsSpecified + ? model.Options.Value.Select(SocketApplicationCommandOption.Create).ToImmutableArray() + : ImmutableArray.Create(); + } + + /// + public Task DeleteAsync(RequestOptions options = null) + => InteractionHelper.DeleteUnknownApplicationCommandAsync(Discord, GuildId, this, options); + + /// + public Task ModifyAsync(Action func, RequestOptions options = null) + { + return ModifyAsync(func, options); + } + + /// + public async Task ModifyAsync(Action func, RequestOptions options = null) where TArg : ApplicationCommandProperties + { + var command = IsGlobalCommand + ? await InteractionHelper.ModifyGlobalCommandAsync(Discord, this, func, options).ConfigureAwait(false) + : await InteractionHelper.ModifyGuildCommandAsync(Discord, this, GuildId.Value, func, options); + + Update(command); + } + #endregion + + #region IApplicationCommand + IReadOnlyCollection IApplicationCommand.Options => Options; + #endregion + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommandChoice.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommandChoice.cs new file mode 100644 index 000000000..e70efa27b --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommandChoice.cs @@ -0,0 +1,29 @@ +using Model = Discord.API.ApplicationCommandOptionChoice; + +namespace Discord.WebSocket +{ + /// + /// Represents a choice for a . + /// + public class SocketApplicationCommandChoice : IApplicationCommandOptionChoice + { + /// + public string Name { get; private set; } + + /// + public object Value { get; private set; } + + internal SocketApplicationCommandChoice() { } + internal static SocketApplicationCommandChoice Create(Model model) + { + var entity = new SocketApplicationCommandChoice(); + entity.Update(model); + return entity; + } + internal void Update(Model model) + { + Name = model.Name; + Value = model.Value; + } + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommandOption.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommandOption.cs new file mode 100644 index 000000000..a19068d48 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommandOption.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Model = Discord.API.ApplicationCommandOption; + +namespace Discord.WebSocket +{ + /// + /// Represents an option for a . + /// + public class SocketApplicationCommandOption : IApplicationCommandOption + { + /// + public string Name { get; private set; } + + /// + public ApplicationCommandOptionType Type { get; private set; } + + /// + public string Description { get; private set; } + + /// + public bool? IsDefault { get; private set; } + + /// + public bool? IsRequired { get; private set; } + + /// + public double? MinValue { get; private set; } + + /// + public double? MaxValue { get; private set; } + + /// + /// Choices for string and int types for the user to pick from. + /// + public IReadOnlyCollection Choices { get; private set; } + + /// + /// If the option is a subcommand or subcommand group type, this nested options will be the parameters. + /// + public IReadOnlyCollection Options { get; private set; } + + /// + /// The allowed channel types for this option. + /// + public IReadOnlyCollection ChannelTypes { get; private set; } + + internal SocketApplicationCommandOption() { } + internal static SocketApplicationCommandOption Create(Model model) + { + var entity = new SocketApplicationCommandOption(); + entity.Update(model); + return entity; + } + + internal void Update(Model model) + { + Name = model.Name; + Type = model.Type; + Description = model.Description; + + IsDefault = model.Default.ToNullable(); + + IsRequired = model.Required.ToNullable(); + + MinValue = model.MinValue.ToNullable(); + + MaxValue = model.MaxValue.ToNullable(); + + Choices = model.Choices.IsSpecified + ? model.Choices.Value.Select(SocketApplicationCommandChoice.Create).ToImmutableArray() + : ImmutableArray.Create(); + + Options = model.Options.IsSpecified + ? model.Options.Value.Select(Create).ToImmutableArray() + : ImmutableArray.Create(); + + ChannelTypes = model.ChannelTypes.IsSpecified + ? model.ChannelTypes.Value.ToImmutableArray() + : ImmutableArray.Create(); + } + + IReadOnlyCollection IApplicationCommandOption.Choices => Choices; + IReadOnlyCollection IApplicationCommandOption.Options => Options; + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketCommandBase.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketCommandBase.cs new file mode 100644 index 000000000..92303d488 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketCommandBase.cs @@ -0,0 +1,300 @@ +using Discord.Net.Rest; +using Discord.Rest; +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using DataModel = Discord.API.ApplicationCommandInteractionData; +using Model = Discord.API.Interaction; + +namespace Discord.WebSocket +{ + /// + /// Base class for User, Message, and Slash command interactions. + /// + public class SocketCommandBase : SocketInteraction + { + /// + /// Gets the name of the invoked command. + /// + public string CommandName + => Data.Name; + + /// + /// Gets the id of the invoked command. + /// + public ulong CommandId + => Data.Id; + + /// + /// The data associated with this interaction. + /// + internal new SocketCommandBaseData Data { get; } + + public override bool HasResponded { get; internal set; } + + private object _lock = new object(); + + internal SocketCommandBase(DiscordSocketClient client, Model model, ISocketMessageChannel channel) + : base(client, model.Id, channel) + { + var dataModel = model.Data.IsSpecified + ? (DataModel)model.Data.Value + : null; + + ulong? guildId = null; + if (Channel is SocketGuildChannel guildChannel) + guildId = guildChannel.Guild.Id; + + Data = SocketCommandBaseData.Create(client, dataModel, model.Id, guildId); + } + + internal new static SocketInteraction Create(DiscordSocketClient client, Model model, ISocketMessageChannel channel) + { + var entity = new SocketCommandBase(client, model, channel); + entity.Update(model); + return entity; + } + + internal override void Update(Model model) + { + var data = model.Data.IsSpecified + ? (DataModel)model.Data.Value + : null; + + Data.Update(data); + + base.Update(model); + } + + /// + public override async Task RespondAsync( + string text = null, + Embed[] embeds = null, + bool isTTS = false, + bool ephemeral = false, + AllowedMentions allowedMentions = null, + RequestOptions options = null, + MessageComponent component = null, + Embed embed = null) + { + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + if (!InteractionHelper.CanSendResponse(this)) + throw new TimeoutException($"Cannot respond to an interaction after {InteractionHelper.ResponseTimeLimit} seconds!"); + + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + + // check that user flag and user Id list are exclusive, same with role flag and role Id list + if (allowedMentions != null && allowedMentions.AllowedTypes.HasValue) + { + if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Users) && + allowedMentions.UserIds != null && allowedMentions.UserIds.Count > 0) + { + throw new ArgumentException("The Users flag is mutually exclusive with the list of User Ids.", nameof(allowedMentions)); + } + + if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Roles) && + allowedMentions.RoleIds != null && allowedMentions.RoleIds.Count > 0) + { + throw new ArgumentException("The Roles flag is mutually exclusive with the list of Role Ids.", nameof(allowedMentions)); + } + } + + var response = new API.InteractionResponse + { + Type = InteractionResponseType.ChannelMessageWithSource, + Data = new API.InteractionCallbackData + { + Content = text, + AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, + Embeds = embeds.Select(x => x.ToModel()).ToArray(), + TTS = isTTS, + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified, + Flags = ephemeral ? MessageFlags.Ephemeral : Optional.Unspecified + } + }; + + lock (_lock) + { + if (HasResponded) + { + throw new InvalidOperationException("Cannot respond twice to the same interaction"); + } + } + + await InteractionHelper.SendInteractionResponseAsync(Discord, response, Id, Token, options).ConfigureAwait(false); + + lock (_lock) + { + HasResponded = true; + } + } + + /// + public override async Task FollowupAsync( + string text = null, + Embed[] embeds = null, + bool isTTS = false, + bool ephemeral = false, + AllowedMentions allowedMentions = null, + RequestOptions options = null, + MessageComponent component = null, + Embed embed = null) + { + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + + var args = new API.Rest.CreateWebhookMessageParams + { + Content = text, + AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, + IsTTS = isTTS, + Embeds = embeds.Select(x => x.ToModel()).ToArray(), + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified + }; + + if (ephemeral) + args.Flags = MessageFlags.Ephemeral; + + return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options); + } + + /// + public override async Task FollowupWithFileAsync( + Stream fileStream, + string fileName, + string text = null, + Embed[] embeds = null, + bool isTTS = false, + bool ephemeral = false, + AllowedMentions allowedMentions = null, + RequestOptions options = null, + MessageComponent component = null, + Embed embed = null) + { + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + Preconditions.NotNull(fileStream, nameof(fileStream), "File Stream must have data"); + Preconditions.NotNullOrEmpty(fileName, nameof(fileName), "File Name must not be empty or null"); + + var args = new API.Rest.CreateWebhookMessageParams + { + Content = text, + AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, + IsTTS = isTTS, + Embeds = embeds.Select(x => x.ToModel()).ToArray(), + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified, + File = fileStream is not null ? new MultipartFile(fileStream, fileName) : Optional.Unspecified + }; + + if (ephemeral) + args.Flags = MessageFlags.Ephemeral; + + return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options); + } + + /// + public override async Task FollowupWithFileAsync( + string filePath, + string text = null, + string fileName = null, + Embed[] embeds = null, + bool isTTS = false, + bool ephemeral = false, + AllowedMentions allowedMentions = null, + RequestOptions options = null, + MessageComponent component = null, + Embed embed = null) + { + if (!IsValidToken) + throw new InvalidOperationException("Interaction token is no longer valid"); + + embeds ??= Array.Empty(); + if (embed != null) + embeds = new[] { embed }.Concat(embeds).ToArray(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Length, 10, nameof(embeds), "A max of 10 embeds are allowed."); + Preconditions.NotNullOrEmpty(filePath, nameof(filePath), "Path must exist"); + + fileName ??= Path.GetFileName(filePath); + Preconditions.NotNullOrEmpty(fileName, nameof(fileName), "File Name must not be empty or null"); + + var args = new API.Rest.CreateWebhookMessageParams + { + Content = text, + AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, + IsTTS = isTTS, + Embeds = embeds.Select(x => x.ToModel()).ToArray(), + Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified, + File = !string.IsNullOrEmpty(filePath) ? new MultipartFile(new MemoryStream(File.ReadAllBytes(filePath), false), fileName) : Optional.Unspecified + }; + + if (ephemeral) + args.Flags = MessageFlags.Ephemeral; + + return await InteractionHelper.SendFollowupAsync(Discord.Rest, args, Token, Channel, options); + } + + /// + /// Acknowledges this interaction with the . + /// + /// + /// A task that represents the asynchronous operation of acknowledging the interaction. + /// + public override async Task DeferAsync(bool ephemeral = false, RequestOptions options = null) + { + if (!InteractionHelper.CanSendResponse(this)) + throw new TimeoutException($"Cannot defer an interaction after {InteractionHelper.ResponseTimeLimit} seconds!"); + + var response = new API.InteractionResponse + { + Type = InteractionResponseType.DeferredChannelMessageWithSource, + Data = new API.InteractionCallbackData + { + Flags = ephemeral ? MessageFlags.Ephemeral : Optional.Unspecified + } + }; + + lock (_lock) + { + if (HasResponded) + { + throw new InvalidOperationException("Cannot respond or defer twice to the same interaction"); + } + } + + await Discord.Rest.ApiClient.CreateInteractionResponseAsync(response, Id, Token, options).ConfigureAwait(false); + + lock (_lock) + { + HasResponded = true; + } + } + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketCommandBaseData.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketCommandBaseData.cs new file mode 100644 index 000000000..cb2f01f5f --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketCommandBaseData.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using Model = Discord.API.ApplicationCommandInteractionData; + +namespace Discord.WebSocket +{ + /// + /// Represents the base data tied with the interaction. + /// + public class SocketCommandBaseData : SocketEntity, IApplicationCommandInteractionData where TOption : IApplicationCommandInteractionDataOption + { + /// + public string Name { get; private set; } + + /// + /// The received with this interaction. + /// + public virtual IReadOnlyCollection Options { get; internal set; } + + internal readonly SocketResolvableData ResolvableData; + + private ApplicationCommandType Type { get; set; } + + internal SocketCommandBaseData(DiscordSocketClient client, Model model, ulong? guildId) + : base(client, model.Id) + { + Type = model.Type; + + if (model.Resolved.IsSpecified) + { + ResolvableData = new SocketResolvableData(client, guildId, model); + } + } + + internal static SocketCommandBaseData Create(DiscordSocketClient client, Model model, ulong id, ulong? guildId) + { + var entity = new SocketCommandBaseData(client, model, guildId); + entity.Update(model); + return entity; + } + + internal virtual void Update(Model model) + { + Name = model.Name; + } + + IReadOnlyCollection IApplicationCommandInteractionData.Options + => (IReadOnlyCollection)Options; + } + + /// + /// Represents the base data tied with the interaction. + /// + public class SocketCommandBaseData : SocketCommandBaseData + { + internal SocketCommandBaseData(DiscordSocketClient client, Model model, ulong? guildId) + : base(client, model, guildId) { } + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketResolvableData.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketResolvableData.cs new file mode 100644 index 000000000..c065637ca --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketResolvableData.cs @@ -0,0 +1,109 @@ +using System.Collections.Generic; + +namespace Discord.WebSocket +{ + internal class SocketResolvableData where T : API.IResolvable + { + internal readonly Dictionary GuildMembers + = new Dictionary(); + internal readonly Dictionary Users + = new Dictionary(); + internal readonly Dictionary Channels + = new Dictionary(); + internal readonly Dictionary Roles + = new Dictionary(); + + internal readonly Dictionary Messages + = new Dictionary(); + + internal SocketResolvableData(DiscordSocketClient discord, ulong? guildId, T model) + { + var guild = guildId.HasValue ? discord.GetGuild(guildId.Value) : null; + + var resolved = model.Resolved.Value; + + if (resolved.Users.IsSpecified) + { + foreach (var user in resolved.Users.Value) + { + var socketUser = discord.GetOrCreateUser(discord.State, user.Value); + + Users.Add(ulong.Parse(user.Key), socketUser); + } + } + + if (resolved.Channels.IsSpecified) + { + foreach (var channel in resolved.Channels.Value) + { + SocketChannel socketChannel = guild != null + ? guild.GetChannel(channel.Value.Id) + : discord.GetChannel(channel.Value.Id); + + if (socketChannel == null) + { + var channelModel = guild != null + ? discord.Rest.ApiClient.GetChannelAsync(guild.Id, channel.Value.Id).ConfigureAwait(false).GetAwaiter().GetResult() + : discord.Rest.ApiClient.GetChannelAsync(channel.Value.Id).ConfigureAwait(false).GetAwaiter().GetResult(); + + socketChannel = guild != null + ? SocketGuildChannel.Create(guild, discord.State, channelModel) + : (SocketChannel)SocketChannel.CreatePrivate(discord, discord.State, channelModel); + } + + discord.State.AddChannel(socketChannel); + Channels.Add(ulong.Parse(channel.Key), socketChannel); + } + } + + if (resolved.Members.IsSpecified) + { + foreach (var member in resolved.Members.Value) + { + member.Value.User = resolved.Users.Value[member.Key]; + var user = guild.AddOrUpdateUser(member.Value); + GuildMembers.Add(ulong.Parse(member.Key), user); + } + } + + if (resolved.Roles.IsSpecified) + { + foreach (var role in resolved.Roles.Value) + { + var socketRole = guild.AddOrUpdateRole(role.Value); + Roles.Add(ulong.Parse(role.Key), socketRole); + } + } + + if (resolved.Messages.IsSpecified) + { + foreach (var msg in resolved.Messages.Value) + { + var channel = discord.GetChannel(msg.Value.ChannelId) as ISocketMessageChannel; + + SocketUser author; + if (guild != null) + { + if (msg.Value.WebhookId.IsSpecified) + author = SocketWebhookUser.Create(guild, discord.State, msg.Value.Author.Value, msg.Value.WebhookId.Value); + else + author = guild.GetUser(msg.Value.Author.Value.Id); + } + else + author = (channel as SocketChannel).GetUser(msg.Value.Author.Value.Id); + + if (channel == null) + { + if (!msg.Value.GuildId.IsSpecified) // assume it is a DM + { + channel = discord.CreateDMChannel(msg.Value.ChannelId, msg.Value.Author.Value, discord.State); + } + } + + var message = SocketMessage.Create(discord, discord.State, author, channel, msg.Value); + Messages.Add(message.Id, message); + } + } + } + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs b/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs new file mode 100644 index 000000000..f0465d336 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs @@ -0,0 +1,243 @@ +using Discord.Rest; +using System; +using System.Threading.Tasks; +using Model = Discord.API.Interaction; +using DataModel = Discord.API.ApplicationCommandInteractionData; +using System.IO; + +namespace Discord.WebSocket +{ + /// + /// Represents an Interaction received over the gateway. + /// + public abstract class SocketInteraction : SocketEntity, IDiscordInteraction + { + #region SocketInteraction + /// + /// The this interaction was used in. + /// + public ISocketMessageChannel Channel { get; private set; } + + /// + /// The who triggered this interaction. + /// + public SocketUser User { get; private set; } + + /// + /// The type of this interaction. + /// + public InteractionType Type { get; private set; } + + /// + /// The token used to respond to this interaction. + /// + public string Token { get; private set; } + + /// + /// The data sent with this interaction. + /// + public IDiscordInteractionData Data { get; private set; } + + /// + /// The version of this interaction. + /// + public int Version { get; private set; } + + /// + public DateTimeOffset CreatedAt { get; private set; } + + /// + /// Gets whether or not this interaction has been responded to. + /// + /// + /// This property is locally set -- if you're running multiple bots + /// off the same token then this property won't be in sync with them. + /// + public abstract bool HasResponded { get; internal set; } + + /// + /// if the token is valid for replying to, otherwise . + /// + public bool IsValidToken + => InteractionHelper.CanRespondOrFollowup(this); + + internal SocketInteraction(DiscordSocketClient client, ulong id, ISocketMessageChannel channel) + : base(client, id) + { + Channel = channel; + + CreatedAt = client.UseInteractionSnowflakeDate + ? SnowflakeUtils.FromSnowflake(Id) + : DateTime.UtcNow; + } + + internal static SocketInteraction Create(DiscordSocketClient client, Model model, ISocketMessageChannel channel) + { + if (model.Type == InteractionType.ApplicationCommand) + { + var dataModel = model.Data.IsSpecified + ? (DataModel)model.Data.Value + : null; + + if (dataModel == null) + return null; + + return dataModel.Type switch + { + ApplicationCommandType.Slash => SocketSlashCommand.Create(client, model, channel), + ApplicationCommandType.Message => SocketMessageCommand.Create(client, model, channel), + ApplicationCommandType.User => SocketUserCommand.Create(client, model, channel), + _ => null + }; + } + + if (model.Type == InteractionType.MessageComponent) + return SocketMessageComponent.Create(client, model, channel); + + if (model.Type == InteractionType.ApplicationCommandAutocomplete) + return SocketAutocompleteInteraction.Create(client, model, channel); + + return null; + } + + internal virtual void Update(Model model) + { + Data = model.Data.IsSpecified + ? model.Data.Value + : null; + Token = model.Token; + Version = model.Version; + Type = model.Type; + + if (User == null) + { + if (model.Member.IsSpecified && model.GuildId.IsSpecified) + { + User = SocketGuildUser.Create(Discord.State.GetGuild(model.GuildId.Value), Discord.State, model.Member.Value); + } + else + { + User = SocketGlobalUser.Create(Discord, Discord.State, model.User.Value); + } + } + } + + /// + /// Responds to an Interaction with type . + /// + /// The text of the message to be sent. + /// A array of embeds to send with this response. Max 10. + /// if the message should be read out by a text-to-speech reader, otherwise . + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . + /// The allowed mentions for this response. + /// The request options for this response. + /// A to be sent with this response. + /// A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + /// Message content is too long, length must be less or equal to . + /// The parameters provided were invalid or the token was invalid. + public abstract Task RespondAsync(string text = null, Embed[] embeds = null, bool isTTS = false, + bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null); + + /// + /// Sends a followup message for this interaction. + /// + /// The text of the message to be sent. + /// A array of embeds to send with this response. Max 10. + /// if the message should be read out by a text-to-speech reader, otherwise . + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . + /// The allowed mentions for this response. + /// The request options for this response. + /// A to be sent with this response. + /// A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + /// + /// The sent message. + /// + public abstract Task FollowupAsync(string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, + AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null); + + /// + /// Sends a followup message for this interaction. + /// + /// The text of the message to be sent. + /// The file to upload. + /// The file name of the attachment. + /// A array of embeds to send with this response. Max 10. + /// if the message should be read out by a text-to-speech reader, otherwise . + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . + /// The allowed mentions for this response. + /// The request options for this response. + /// A to be sent with this response. + /// A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + /// + /// The sent message. + /// + public abstract Task FollowupWithFileAsync(Stream fileStream, string fileName, string text = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, + AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null); + + /// + /// Sends a followup message for this interaction. + /// + /// The text of the message to be sent. + /// The file to upload. + /// The file name of the attachment. + /// A array of embeds to send with this response. Max 10. + /// if the message should be read out by a text-to-speech reader, otherwise . + /// if the response should be hidden to everyone besides the invoker of the command, otherwise . + /// The allowed mentions for this response. + /// The request options for this response. + /// A to be sent with this response. + /// A single embed to send with this response. If this is passed alongside an array of embeds, the single embed will be ignored. + /// + /// The sent message. + /// + public abstract Task FollowupWithFileAsync(string filePath, string text = null, string fileName = null, Embed[] embeds = null, bool isTTS = false, bool ephemeral = false, + AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null, Embed embed = null); + + /// + /// Gets the original response for this interaction. + /// + /// The request options for this request. + /// A that represents the initial response. + public Task GetOriginalResponseAsync(RequestOptions options = null) + => InteractionHelper.GetOriginalResponseAsync(Discord, Channel, this, options); + + /// + /// Edits original response for this interaction. + /// + /// A delegate containing the properties to modify the message with. + /// The request options for this request. + /// A that represents the initial response. + public async Task ModifyOriginalResponseAsync(Action func, RequestOptions options = null) + { + var model = await InteractionHelper.ModifyInteractionResponseAsync(Discord, Token, func, options); + return RestInteractionMessage.Create(Discord, model, Token, Channel); + } + + /// + /// Acknowledges this interaction. + /// + /// to send this message ephemerally, otherwise . + /// The request options for this request. + /// + /// A task that represents the asynchronous operation of acknowledging the interaction. + /// + public abstract Task DeferAsync(bool ephemeral = false, RequestOptions options = null); + + #endregion + + #region IDiscordInteraction + /// + async Task IDiscordInteraction.FollowupAsync(string text, Embed[] embeds, bool isTTS, bool ephemeral, AllowedMentions allowedMentions, + RequestOptions options, MessageComponent component, Embed embed) + => await FollowupAsync(text, embeds, isTTS, ephemeral, allowedMentions, options, component, embed).ConfigureAwait(false); + + /// + async Task IDiscordInteraction.GetOriginalResponseAsync(RequestOptions options) + => await GetOriginalResponseAsync(options).ConfigureAwait(false); + + /// + async Task IDiscordInteraction.ModifyOriginalResponseAsync(Action func, RequestOptions options) + => await ModifyOriginalResponseAsync(func, options).ConfigureAwait(false); + #endregion + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Invites/SocketInvite.cs b/src/Discord.Net.WebSocket/Entities/Invites/SocketInvite.cs index 845b48b8b..2b64e170e 100644 --- a/src/Discord.Net.WebSocket/Entities/Invites/SocketInvite.cs +++ b/src/Discord.Net.WebSocket/Entities/Invites/SocketInvite.cs @@ -6,6 +6,9 @@ namespace Discord.WebSocket { + /// + /// Represents a WebSocket-based invite to a guild. + /// [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketInvite : SocketEntity, IInviteMetadata { @@ -28,16 +31,16 @@ ChannelType IInvite.ChannelType { get { - switch (Channel) + return Channel switch { - case IVoiceChannel voiceChannel: return ChannelType.Voice; - case ICategoryChannel categoryChannel: return ChannelType.Category; - case IDMChannel dmChannel: return ChannelType.DM; - case IGroupChannel groupChannel: return ChannelType.Group; - case INewsChannel newsChannel: return ChannelType.News; - case ITextChannel textChannel: return ChannelType.Text; - default: throw new InvalidOperationException("Invalid channel type."); - } + IVoiceChannel voiceChannel => ChannelType.Voice, + ICategoryChannel categoryChannel => ChannelType.Category, + IDMChannel dmChannel => ChannelType.DM, + IGroupChannel groupChannel => ChannelType.Group, + INewsChannel newsChannel => ChannelType.News, + ITextChannel textChannel => ChannelType.Text, + _ => throw new InvalidOperationException("Invalid channel type."), + }; } } /// diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs index 353c26fb8..4be9f4c5a 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs @@ -1,4 +1,5 @@ using Discord.Rest; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -13,8 +14,10 @@ namespace Discord.WebSocket /// public abstract class SocketMessage : SocketEntity, IMessage { + #region SocketMessage private long _timestampTicks; private readonly List _reactions = new List(); + private ImmutableArray _userMentions = ImmutableArray.Create(); /// /// Gets the author of this message. @@ -36,6 +39,9 @@ public abstract class SocketMessage : SocketEntity, IMessage /// public string Content { get; private set; } + /// + public string CleanContent => MessageHelper.SanitizeMessage(this); + /// public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); /// @@ -58,6 +64,14 @@ public abstract class SocketMessage : SocketEntity, IMessage /// public MessageReference Reference { get; private set; } + /// + public IReadOnlyCollection Components { get; private set; } + + /// + /// Gets the interaction this message is a response to. + /// + public MessageInteraction Interaction { get; private set; } + /// public MessageFlags? Flags { get; private set; } @@ -92,20 +106,19 @@ public abstract class SocketMessage : SocketEntity, IMessage /// Collection of WebSocket-based roles. /// public virtual IReadOnlyCollection MentionedRoles => ImmutableArray.Create(); + /// + public virtual IReadOnlyCollection Tags => ImmutableArray.Create(); + /// + public virtual IReadOnlyCollection Stickers => ImmutableArray.Create(); + /// + public IReadOnlyDictionary Reactions => _reactions.GroupBy(r => r.Emote).ToDictionary(x => x.Key, x => new ReactionMetadata { ReactionCount = x.Count(), IsMe = x.Any(y => y.UserId == Discord.CurrentUser.Id) }); /// /// Returns the users mentioned in this message. /// /// /// Collection of WebSocket-based users. /// - public virtual IReadOnlyCollection MentionedUsers => ImmutableArray.Create(); - /// - public virtual IReadOnlyCollection Tags => ImmutableArray.Create(); - /// - public virtual IReadOnlyCollection Stickers => ImmutableArray.Create(); - /// - public IReadOnlyDictionary Reactions => _reactions.GroupBy(r => r.Emote).ToDictionary(x => x.Key, x => new ReactionMetadata { ReactionCount = x.Count(), IsMe = x.Any(y => y.UserId == Discord.CurrentUser.Id) }); - + public IReadOnlyCollection MentionedUsers => _userMentions; /// public DateTimeOffset Timestamp => DateTimeUtils.FromTicks(_timestampTicks); @@ -118,7 +131,10 @@ internal SocketMessage(DiscordSocketClient discord, ulong id, ISocketMessageChan } internal static SocketMessage Create(DiscordSocketClient discord, ClientState state, SocketUser author, ISocketMessageChannel channel, Model model) { - if (model.Type == MessageType.Default || model.Type == MessageType.Reply) + if (model.Type == MessageType.Default || + model.Type == MessageType.Reply || + model.Type == MessageType.ApplicationCommand || + model.Type == MessageType.ThreadStarterMessage) return SocketUserMessage.Create(discord, state, author, channel, model); else return SocketSystemMessage.Create(discord, state, author, channel, model); @@ -131,7 +147,9 @@ internal virtual void Update(ClientState state, Model model) _timestampTicks = model.Timestamp.Value.UtcTicks; if (model.Content.IsSpecified) + { Content = model.Content.Value; + } if (model.Application.IsSpecified) { @@ -167,6 +185,86 @@ internal virtual void Update(ClientState state, Model model) }; } + if (model.Components.IsSpecified) + { + Components = model.Components.Value.Select(x => new ActionRowComponent(x.Components.Select(y => + { + switch (y.Type) + { + case ComponentType.Button: + { + var parsed = (API.ButtonComponent)y; + return new Discord.ButtonComponent( + parsed.Style, + parsed.Label.GetValueOrDefault(), + parsed.Emote.IsSpecified + ? parsed.Emote.Value.Id.HasValue + ? new Emote(parsed.Emote.Value.Id.Value, parsed.Emote.Value.Name, parsed.Emote.Value.Animated.GetValueOrDefault()) + : new Emoji(parsed.Emote.Value.Name) + : null, + parsed.CustomId.GetValueOrDefault(), + parsed.Url.GetValueOrDefault(), + parsed.Disabled.GetValueOrDefault()); + } + case ComponentType.SelectMenu: + { + var parsed = (API.SelectMenuComponent)y; + return new SelectMenuComponent( + parsed.CustomId, + parsed.Options.Select(z => new SelectMenuOption( + z.Label, + z.Value, + z.Description.GetValueOrDefault(), + z.Emoji.IsSpecified + ? z.Emoji.Value.Id.HasValue + ? new Emote(z.Emoji.Value.Id.Value, z.Emoji.Value.Name, z.Emoji.Value.Animated.GetValueOrDefault()) + : new Emoji(z.Emoji.Value.Name) + : null, + z.Default.ToNullable())).ToList(), + parsed.Placeholder.GetValueOrDefault(), + parsed.MinValues, + parsed.MaxValues, + parsed.Disabled + ); + } + default: + return null; + } + }).ToList())).ToImmutableArray(); + } + else + Components = new List(); + + if (model.UserMentions.IsSpecified) + { + var value = model.UserMentions.Value; + if (value.Length > 0) + { + var newMentions = ImmutableArray.CreateBuilder(value.Length); + for (int i = 0; i < value.Length; i++) + { + var val = value[i]; + if (val != null) + { + var user = Channel.GetUserAsync(val.Id, CacheMode.CacheOnly).GetAwaiter().GetResult() as SocketUser; + if (user != null) + newMentions.Add(user); + else + newMentions.Add(SocketUnknownUser.Create(Discord, state, val)); + } + } + _userMentions = newMentions.ToImmutable(); + } + } + + if (model.Interaction.IsSpecified) + { + Interaction = new MessageInteraction(model.Interaction.Value.Id, + model.Interaction.Value.Type, + model.Interaction.Value.Name, + SocketGlobalUser.Create(Discord, state, model.Interaction.Value.User)); + } + if (model.Flags.IsSpecified) Flags = model.Flags.Value; } @@ -183,8 +281,9 @@ public Task DeleteAsync(RequestOptions options = null) /// public override string ToString() => Content; internal SocketMessage Clone() => MemberwiseClone() as SocketMessage; +#endregion - //IMessage + #region IMessage /// IUser IMessage.Author => Author; /// @@ -199,8 +298,16 @@ public Task DeleteAsync(RequestOptions options = null) IReadOnlyCollection IMessage.MentionedRoleIds => MentionedRoles.Select(x => x.Id).ToImmutableArray(); /// IReadOnlyCollection IMessage.MentionedUserIds => MentionedUsers.Select(x => x.Id).ToImmutableArray(); + + /// + IReadOnlyCollection IMessage.Components => Components; + + /// + IMessageInteraction IMessage.Interaction => Interaction; + /// - IReadOnlyCollection IMessage.Stickers => Stickers; + IReadOnlyCollection IMessage.Stickers => Stickers; + internal void AddReaction(SocketReaction reaction) { @@ -238,5 +345,6 @@ public Task RemoveAllReactionsForEmoteAsync(IEmote emote, RequestOptions options /// public IAsyncEnumerable> GetReactionUsersAsync(IEmote emote, int limit, RequestOptions options = null) => MessageHelper.GetReactionUsersAsync(this, emote, limit, Discord, options); + #endregion } } diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs index 597544f4d..e5776a089 100644 --- a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs +++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs @@ -22,8 +22,7 @@ public class SocketUserMessage : SocketMessage, IUserMessage private ImmutableArray _embeds = ImmutableArray.Create(); private ImmutableArray _tags = ImmutableArray.Create(); private ImmutableArray _roleMentions = ImmutableArray.Create(); - private ImmutableArray _userMentions = ImmutableArray.Create(); - private ImmutableArray _stickers = ImmutableArray.Create(); + private ImmutableArray _stickers = ImmutableArray.Create(); /// public override bool IsTTS => _isTTS; @@ -46,9 +45,7 @@ public class SocketUserMessage : SocketMessage, IUserMessage /// public override IReadOnlyCollection MentionedRoles => _roleMentions; /// - public override IReadOnlyCollection MentionedUsers => _userMentions; - /// - public override IReadOnlyCollection Stickers => _stickers; + public override IReadOnlyCollection Stickers => _stickers; /// public IUserMessage ReferencedMessage => _referencedMessage; @@ -108,32 +105,10 @@ internal override void Update(ClientState state, Model model) _embeds = ImmutableArray.Create(); } - if (model.UserMentions.IsSpecified) - { - var value = model.UserMentions.Value; - if (value.Length > 0) - { - var newMentions = ImmutableArray.CreateBuilder(value.Length); - for (int i = 0; i < value.Length; i++) - { - var val = value[i]; - if (val.Object != null) - { - var user = Channel.GetUserAsync(val.Object.Id, CacheMode.CacheOnly).GetAwaiter().GetResult() as SocketUser; - if (user != null) - newMentions.Add(user); - else - newMentions.Add(SocketUnknownUser.Create(Discord, state, val.Object)); - } - } - _userMentions = newMentions.ToImmutable(); - } - } - if (model.Content.IsSpecified) { var text = model.Content.Value; - _tags = MessageHelper.ParseTags(text, Channel, guild, _userMentions); + _tags = MessageHelper.ParseTags(text, Channel, guild, MentionedUsers); model.Content = text; } @@ -162,18 +137,40 @@ internal override void Update(ClientState state, Model model) _referencedMessage = SocketUserMessage.Create(Discord, state, refMsgAuthor, Channel, refMsg); } - if (model.Stickers.IsSpecified) + if (model.StickerItems.IsSpecified) { - var value = model.Stickers.Value; + var value = model.StickerItems.Value; if (value.Length > 0) { - var stickers = ImmutableArray.CreateBuilder(value.Length); + var stickers = ImmutableArray.CreateBuilder(value.Length); for (int i = 0; i < value.Length; i++) - stickers.Add(Sticker.Create(value[i])); + { + var stickerItem = value[i]; + SocketSticker sticker = null; + + if (guild != null) + sticker = guild.GetSticker(stickerItem.Id); + + if (sticker == null) + sticker = Discord.GetSticker(stickerItem.Id); + + // if they want to auto resolve + if (Discord.AlwaysResolveStickers) + { + sticker = Task.Run(async () => await Discord.GetStickerAsync(stickerItem.Id).ConfigureAwait(false)).GetAwaiter().GetResult(); + } + + // if its still null, create an unknown + if (sticker == null) + sticker = SocketUnknownSticker.Create(Discord, stickerItem); + + stickers.Add(sticker); + } + _stickers = stickers.ToImmutable(); } else - _stickers = ImmutableArray.Create(); + _stickers = ImmutableArray.Create(); } } diff --git a/src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs b/src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs index e6aac2c04..1e90b8f5c 100644 --- a/src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs +++ b/src/Discord.Net.WebSocket/Entities/Roles/SocketRole.cs @@ -1,6 +1,6 @@ using Discord.Rest; using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; @@ -14,6 +14,7 @@ namespace Discord.WebSocket [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketRole : SocketEntity, IRole { + #region SocketRole /// /// Gets the guild that owns this role. /// @@ -32,6 +33,10 @@ public class SocketRole : SocketEntity, IRole public bool IsMentionable { get; private set; } /// public string Name { get; private set; } + /// + public Emoji Emoji { get; private set; } + /// + public string Icon { get; private set; } /// public GuildPermissions Permissions { get; private set; } /// @@ -50,7 +55,11 @@ public class SocketRole : SocketEntity, IRole public bool IsEveryone => Id == Guild.Id; /// public string Mention => IsEveryone ? "@everyone" : MentionUtils.MentionRole(Id); - public IEnumerable Members + + /// + /// Returns an IEnumerable containing all that have this role. + /// + public IEnumerable Members => Guild.Users.Where(x => x.Roles.Any(r => r.Id == Id)); internal SocketRole(SocketGuild guild, ulong id) @@ -75,6 +84,16 @@ internal void Update(ClientState state, Model model) Permissions = new GuildPermissions(model.Permissions); if (model.Tags.IsSpecified) Tags = model.Tags.Value.ToEntity(); + + if (model.Icon.IsSpecified) + { + Icon = model.Icon.Value; + } + + if (model.Emoji.IsSpecified) + { + Emoji = new Emoji(model.Emoji.Value); + } } /// @@ -84,6 +103,10 @@ public Task ModifyAsync(Action func, RequestOptions options = nu public Task DeleteAsync(RequestOptions options = null) => RoleHelper.DeleteAsync(this, Discord, options); + /// + public string GetIconUrl() + => CDN.GetGuildRoleIconUrl(Id, Icon); + /// /// Gets the name of the role. /// @@ -96,9 +119,11 @@ public Task DeleteAsync(RequestOptions options = null) /// public int CompareTo(IRole role) => RoleUtils.Compare(this, role); + #endregion - //IRole + #region IRole /// IGuild IRole.Guild => Guild; + #endregion } } diff --git a/src/Discord.Net.WebSocket/Entities/Stickers/SocketCustomSticker.cs b/src/Discord.Net.WebSocket/Entities/Stickers/SocketCustomSticker.cs new file mode 100644 index 000000000..6a5104012 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Stickers/SocketCustomSticker.cs @@ -0,0 +1,81 @@ +using Discord.Rest; +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using Model = Discord.API.Sticker; + +namespace Discord.WebSocket +{ + /// + /// Represents a custom sticker within a guild received over the gateway. + /// + [DebuggerDisplay(@"{DebuggerDisplay,nq}")] + public class SocketCustomSticker : SocketSticker, ICustomSticker + { + #region SocketCustomSticker + /// + /// Gets the user that uploaded the guild sticker. + /// + /// + /// + /// This may return in the WebSocket implementation due to incomplete user collection in + /// large guilds, or the bot doesn't have the MANAGE_EMOJIS_AND_STICKERS permission. + /// + /// + public SocketGuildUser Author + => AuthorId.HasValue ? Guild.GetUser(AuthorId.Value) : null; + + /// + /// Gets the guild the sticker was created in. + /// + public SocketGuild Guild { get; } + + /// + public ulong? AuthorId { get; set; } + + internal SocketCustomSticker(DiscordSocketClient client, ulong id, SocketGuild guild, ulong? authorId = null) + : base(client, id) + { + Guild = guild; + AuthorId = authorId; + } + + internal static SocketCustomSticker Create(DiscordSocketClient client, Model model, SocketGuild guild, ulong? authorId = null) + { + var entity = new SocketCustomSticker(client, model.Id, guild, authorId); + entity.Update(model); + return entity; + } + + /// + public async Task ModifyAsync(Action func, RequestOptions options = null) + { + if (!Guild.CurrentUser.GuildPermissions.Has(GuildPermission.ManageEmojisAndStickers)) + throw new InvalidOperationException($"Missing permission {nameof(GuildPermission.ManageEmojisAndStickers)}"); + + var model = await GuildHelper.ModifyStickerAsync(Discord, Guild.Id, this, func, options); + + Update(model); + } + + /// + public async Task DeleteAsync(RequestOptions options = null) + { + await GuildHelper.DeleteStickerAsync(Discord, Guild.Id, this, options); + Guild.RemoveSticker(Id); + } + + internal SocketCustomSticker Clone() => MemberwiseClone() as SocketCustomSticker; + + private new string DebuggerDisplay => Guild == null ? base.DebuggerDisplay : $"{Name} in {Guild.Name} ({Id})"; + #endregion + + #region ICustomSticker + ulong? ICustomSticker.AuthorId + => AuthorId; + + IGuild ICustomSticker.Guild + => Guild; + #endregion + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Stickers/SocketSticker.cs b/src/Discord.Net.WebSocket/Entities/Stickers/SocketSticker.cs new file mode 100644 index 000000000..ee45720b5 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Stickers/SocketSticker.cs @@ -0,0 +1,92 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; +using Model = Discord.API.Sticker; + +namespace Discord.WebSocket +{ + /// + /// Represents a general sticker received over the gateway. + /// + [DebuggerDisplay(@"{DebuggerDisplay,nq}")] + public class SocketSticker : SocketEntity, ISticker + { + /// + public virtual ulong PackId { get; private set; } + + /// + public string Name { get; protected set; } + + /// + public virtual string Description { get; private set; } + + /// + public virtual IReadOnlyCollection Tags { get; private set; } + + /// + public virtual StickerType Type { get; private set; } + + /// + public StickerFormatType Format { get; protected set; } + + /// + public virtual bool? IsAvailable { get; protected set; } + + /// + public virtual int? SortOrder { get; private set; } + + /// + public string GetStickerUrl() + => CDN.GetStickerUrl(Id, Format); + + internal SocketSticker(DiscordSocketClient client, ulong id) + : base(client, id) { } + + internal static SocketSticker Create(DiscordSocketClient client, Model model) + { + var entity = model.GuildId.IsSpecified + ? new SocketCustomSticker(client, model.Id, client.GetGuild(model.GuildId.Value), model.User.IsSpecified ? model.User.Value.Id : null) + : new SocketSticker(client, model.Id); + + entity.Update(model); + return entity; + } + + internal virtual void Update(Model model) + { + Name = model.Name; + Description = model.Description; + PackId = model.PackId; + IsAvailable = model.Available; + Format = model.FormatType; + Type = model.Type; + SortOrder = model.SortValue; + + Tags = model.Tags.IsSpecified + ? model.Tags.Value.Split(',').Select(x => x.Trim()).ToImmutableArray() + : ImmutableArray.Create(); + } + + internal string DebuggerDisplay => $"{Name} ({Id})"; + + /// + public override bool Equals(object obj) + { + if (obj is Model stickerModel) + { + return stickerModel.Name == Name && + stickerModel.Description == Description && + stickerModel.FormatType == Format && + stickerModel.Id == Id && + stickerModel.PackId == PackId && + stickerModel.Type == Type && + stickerModel.SortValue == SortOrder && + stickerModel.Available == IsAvailable && + (!stickerModel.Tags.IsSpecified || stickerModel.Tags.Value == string.Join(", ", Tags)); + } + + return base.Equals(obj); + } + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Stickers/SocketUnknownSticker.cs b/src/Discord.Net.WebSocket/Entities/Stickers/SocketUnknownSticker.cs new file mode 100644 index 000000000..ca7d2d0f1 --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Stickers/SocketUnknownSticker.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading.Tasks; +using Model = Discord.API.StickerItem; + +namespace Discord.WebSocket +{ + /// + /// Represents an unknown sticker received over the gateway. + /// + [DebuggerDisplay(@"{DebuggerDisplay,nq}")] + public class SocketUnknownSticker : SocketSticker + { + /// + public override IReadOnlyCollection Tags + => null; + + /// + public override string Description + => null; + + /// + public override ulong PackId + => 0; + /// + public override bool? IsAvailable + => null; + + /// + public override int? SortOrder + => null; + + /// + public new StickerType? Type + => null; + + internal SocketUnknownSticker(DiscordSocketClient client, ulong id) + : base(client, id) { } + + internal static SocketUnknownSticker Create(DiscordSocketClient client, Model model) + { + var entity = new SocketUnknownSticker(client, model.Id); + entity.Update(model); + return entity; + } + + internal void Update(Model model) + { + Name = model.Name; + Format = model.FormatType; + } + + /// + /// Attempts to try to find the sticker. + /// + /// + /// The sticker representing this unknown stickers Id, if none is found then . + /// + public Task ResolveAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) + => Discord.GetStickerAsync(Id, mode, options); + + private new string DebuggerDisplay => $"{Name} ({Id})"; + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs index 15c5182fc..3a1ad23b6 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs @@ -47,7 +47,7 @@ internal void RemoveRef(DiscordSocketClient discord) discord.RemoveUser(Id); } } - + internal void Update(ClientState state, PresenceModel model) { Presence = SocketPresence.Create(model); diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGroupUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGroupUser.cs index 676c0a86c..fe19a41ec 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGroupUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGroupUser.cs @@ -1,11 +1,16 @@ +using System; using System.Diagnostics; using Model = Discord.API.User; namespace Discord.WebSocket { + /// + /// Represents a WebSocket-based group user. + /// [DebuggerDisplay("{DebuggerDisplay,nq}")] public class SocketGroupUser : SocketUser, IGroupUser { + #region SocketGroupUser /// /// Gets the group channel of the user. /// @@ -45,8 +50,9 @@ internal static SocketGroupUser Create(SocketGroupChannel channel, ClientState s private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")}, Group)"; internal new SocketGroupUser Clone() => MemberwiseClone() as SocketGroupUser; + #endregion - //IVoiceState + #region IVoiceState /// bool IVoiceState.IsDeafened => false; /// @@ -63,5 +69,8 @@ internal static SocketGroupUser Create(SocketGroupChannel channel, ClientState s string IVoiceState.VoiceSessionId => null; /// bool IVoiceState.IsStreaming => false; + /// + DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null; + #endregion } } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs index 444c76ffa..147456cb0 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs @@ -18,6 +18,7 @@ namespace Discord.WebSocket [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketGuildUser : SocketUser, IGuildUser { + #region SocketGuildUser private long? _premiumSinceTicks; private long? _joinedAtTicks; private ImmutableArray _roleIds; @@ -29,7 +30,8 @@ public class SocketGuildUser : SocketUser, IGuildUser public SocketGuild Guild { get; } /// public string Nickname { get; private set; } - + /// + public string GuildAvatarId { get; private set; } /// public override bool IsBot { get { return GlobalUser.IsBot; } internal set { GlobalUser.IsBot = value; } } /// @@ -38,6 +40,7 @@ public class SocketGuildUser : SocketUser, IGuildUser public override ushort DiscriminatorValue { get { return GlobalUser.DiscriminatorValue; } internal set { GlobalUser.DiscriminatorValue = value; } } /// public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } + /// public GuildPermissions GuildPermissions => new GuildPermissions(Permissions.ResolveGuild(Guild, this)); internal override SocketPresence Presence { get; set; } @@ -57,7 +60,11 @@ public class SocketGuildUser : SocketUser, IGuildUser /// public bool IsStreaming => VoiceState?.IsStreaming ?? false; /// + public DateTimeOffset? RequestToSpeakTimestamp => VoiceState?.RequestToSpeakTimestamp ?? null; + /// public bool? IsPending { get; private set; } + + /// public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks); /// @@ -87,7 +94,7 @@ public IReadOnlyCollection Roles /// Returns the position of the user within the role hierarchy. /// /// - /// The returned value equal to the position of the highest role the user has, or + /// The returned value equal to the position of the highest role the user has, or /// if user is the server owner. /// public int Hierarchy @@ -144,6 +151,8 @@ internal void Update(ClientState state, MemberModel model) _joinedAtTicks = model.JoinedAt.Value.UtcTicks; if (model.Nick.IsSpecified) Nickname = model.Nick.Value; + if (model.Avatar.IsSpecified) + GuildAvatarId = model.Avatar.Value; if (model.Roles.IsSpecified) UpdateRoles(model.Roles.Value); if (model.PremiumSince.IsSpecified) @@ -208,11 +217,14 @@ public Task RemoveRolesAsync(IEnumerable roles, RequestOptions options = /// public ChannelPermissions GetPermissions(IGuildChannel channel) => new ChannelPermissions(Permissions.ResolveChannel(Guild, this, channel, GuildPermissions.RawValue)); + public string GetGuildAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) + => CDN.GetGuildUserAvatarUrl(Id, Guild.Id, GuildAvatarId, size, format); private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")}, Guild)"; internal new SocketGuildUser Clone() => MemberwiseClone() as SocketGuildUser; + #endregion - //IGuildUser + #region IGuildUser /// IGuild IGuildUser.Guild => Guild; /// @@ -223,5 +235,6 @@ public ChannelPermissions GetPermissions(IGuildChannel channel) //IVoiceState /// IVoiceChannel IVoiceState.VoiceChannel => VoiceChannel; + #endregion } } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs new file mode 100644 index 000000000..b2311dd7d --- /dev/null +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Model = Discord.API.ThreadMember; +using System.Collections.Immutable; + +namespace Discord.WebSocket +{ + /// + /// Represents a thread user received over the gateway. + /// + public class SocketThreadUser : SocketUser, IGuildUser + { + /// + /// Gets the this user is in. + /// + public SocketThreadChannel Thread { get; private set; } + + /// + /// Gets the timestamp for when this user joined this thread. + /// + public DateTimeOffset ThreadJoinedAt { get; private set; } + + /// + /// Gets the guild this user is in. + /// + public SocketGuild Guild { get; private set; } + + /// + public DateTimeOffset? JoinedAt + => GuildUser.JoinedAt; + + /// + public string Nickname + => GuildUser.Nickname; + + /// + public DateTimeOffset? PremiumSince + => GuildUser.PremiumSince; + + /// + public bool? IsPending + => GuildUser.IsPending; + /// + public int Hierarchy + => GuildUser.Hierarchy; + + /// + public override string AvatarId + { + get => GuildUser.AvatarId; + internal set => GuildUser.AvatarId = value; + } + /// + public string GuildAvatarId + => GuildUser.GuildAvatarId; + + /// + public override ushort DiscriminatorValue + { + get => GuildUser.DiscriminatorValue; + internal set => GuildUser.DiscriminatorValue = value; + } + + /// + public override bool IsBot + { + get => GuildUser.IsBot; + internal set => GuildUser.IsBot = value; + } + + /// + public override bool IsWebhook + => GuildUser.IsWebhook; + + /// + public override string Username + { + get => GuildUser.Username; + internal set => GuildUser.Username = value; + } + + /// + public bool IsDeafened + => GuildUser.IsDeafened; + + /// + public bool IsMuted + => GuildUser.IsMuted; + + /// + public bool IsSelfDeafened + => GuildUser.IsSelfDeafened; + + /// + public bool IsSelfMuted + => GuildUser.IsSelfMuted; + + /// + public bool IsSuppressed + => GuildUser.IsSuppressed; + + /// + public IVoiceChannel VoiceChannel + => GuildUser.VoiceChannel; + + /// + public string VoiceSessionId + => GuildUser.VoiceSessionId; + + /// + public bool IsStreaming + => GuildUser.IsStreaming; + + /// + public DateTimeOffset? RequestToSpeakTimestamp + => GuildUser.RequestToSpeakTimestamp; + + private SocketGuildUser GuildUser { get; set; } + + internal SocketThreadUser(SocketGuild guild, SocketThreadChannel thread, SocketGuildUser member) + : base(guild.Discord, member.Id) + { + Thread = thread; + Guild = guild; + GuildUser = member; + } + + internal static SocketThreadUser Create(SocketGuild guild, SocketThreadChannel thread, Model model, SocketGuildUser member) + { + var entity = new SocketThreadUser(guild, thread, member); + entity.Update(model); + return entity; + } + + internal void Update(Model model) + { + ThreadJoinedAt = model.JoinTimestamp; + + if (model.Presence.IsSpecified) + { + GuildUser.Update(Discord.State, model.Presence.Value, true); + } + + if (model.Member.IsSpecified) + { + GuildUser.Update(Discord.State, model.Member.Value); + } + } + + /// + public ChannelPermissions GetPermissions(IGuildChannel channel) => GuildUser.GetPermissions(channel); + + /// + public Task KickAsync(string reason = null, RequestOptions options = null) => GuildUser.KickAsync(reason, options); + + /// + public Task ModifyAsync(Action func, RequestOptions options = null) => GuildUser.ModifyAsync(func, options); + + /// + public Task AddRoleAsync(ulong roleId, RequestOptions options = null) => GuildUser.AddRoleAsync(roleId, options); + + /// + public Task AddRoleAsync(IRole role, RequestOptions options = null) => GuildUser.AddRoleAsync(role, options); + + /// + public Task AddRolesAsync(IEnumerable roleIds, RequestOptions options = null) => GuildUser.AddRolesAsync(roleIds, options); + + /// + public Task AddRolesAsync(IEnumerable roles, RequestOptions options = null) => GuildUser.AddRolesAsync(roles, options); + + /// + public Task RemoveRoleAsync(ulong roleId, RequestOptions options = null) => GuildUser.RemoveRoleAsync(roleId, options); + + /// + public Task RemoveRoleAsync(IRole role, RequestOptions options = null) => GuildUser.RemoveRoleAsync(role, options); + + /// + public Task RemoveRolesAsync(IEnumerable roleIds, RequestOptions options = null) => GuildUser.RemoveRolesAsync(roleIds, options); + + /// + public Task RemoveRolesAsync(IEnumerable roles, RequestOptions options = null) => GuildUser.RemoveRolesAsync(roles, options); + + /// + GuildPermissions IGuildUser.GuildPermissions => GuildUser.GuildPermissions; + + /// + IGuild IGuildUser.Guild => Guild; + + /// + ulong IGuildUser.GuildId => Guild.Id; + + /// + IReadOnlyCollection IGuildUser.RoleIds => GuildUser.Roles.Select(x => x.Id).ToImmutableArray(); + + string IGuildUser.GetGuildAvatarUrl(ImageFormat format, ushort size) => GuildUser.GetGuildAvatarUrl(format, size); + + internal override SocketGlobalUser GlobalUser => GuildUser.GlobalUser; + + internal override SocketPresence Presence { get => GuildUser.Presence; set => GuildUser.Presence = value; } + + /// + /// Gets the guild user of this thread user. + /// + /// + public static explicit operator SocketGuildUser(SocketThreadUser user) => user.GuildUser; + } +} diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs index 840a1c30b..a15f7e747 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketUnknownUser.cs @@ -19,9 +19,10 @@ public class SocketUnknownUser : SocketUser public override ushort DiscriminatorValue { get; internal set; } /// public override string AvatarId { get; internal set; } + /// public override bool IsBot { get; internal set; } - + /// public override bool IsWebhook => false; /// diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketVoiceState.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketVoiceState.cs index 5bf36e796..816a839fc 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketVoiceState.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketVoiceState.cs @@ -13,7 +13,7 @@ public struct SocketVoiceState : IVoiceState /// /// Initializes a default with everything set to null or false. /// - public static readonly SocketVoiceState Default = new SocketVoiceState(null, null, false, false, false, false, false, false); + public static readonly SocketVoiceState Default = new SocketVoiceState(null, null, null, false, false, false, false, false, false); [Flags] private enum Flags : byte @@ -35,6 +35,8 @@ private enum Flags : byte public SocketVoiceChannel VoiceChannel { get; } /// public string VoiceSessionId { get; } + /// + public DateTimeOffset? RequestToSpeakTimestamp { get; private set; } /// public bool IsMuted => (_voiceStates & Flags.Muted) != 0; @@ -48,11 +50,13 @@ private enum Flags : byte public bool IsSelfDeafened => (_voiceStates & Flags.SelfDeafened) != 0; /// public bool IsStreaming => (_voiceStates & Flags.SelfStream) != 0; + - internal SocketVoiceState(SocketVoiceChannel voiceChannel, string sessionId, bool isSelfMuted, bool isSelfDeafened, bool isMuted, bool isDeafened, bool isSuppressed, bool isStream) + internal SocketVoiceState(SocketVoiceChannel voiceChannel, DateTimeOffset? requestToSpeak, string sessionId, bool isSelfMuted, bool isSelfDeafened, bool isMuted, bool isDeafened, bool isSuppressed, bool isStream) { VoiceChannel = voiceChannel; VoiceSessionId = sessionId; + RequestToSpeakTimestamp = requestToSpeak; Flags voiceStates = Flags.Normal; if (isSelfMuted) @@ -71,7 +75,7 @@ internal SocketVoiceState(SocketVoiceChannel voiceChannel, string sessionId, boo } internal static SocketVoiceState Create(SocketVoiceChannel voiceChannel, Model model) { - return new SocketVoiceState(voiceChannel, model.SessionId, model.SelfMute, model.SelfDeaf, model.Mute, model.Deaf, model.Suppress, model.SelfStream); + return new SocketVoiceState(voiceChannel, model.RequestToSpeakTimestamp.IsSpecified ? model.RequestToSpeakTimestamp.Value : null, model.SessionId, model.SelfMute, model.SelfDeaf, model.Mute, model.Deaf, model.Suppress, model.SelfStream); } /// diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs index 404ab116d..bccfe1a29 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketWebhookUser.cs @@ -13,6 +13,7 @@ namespace Discord.WebSocket [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketWebhookUser : SocketUser, IWebhookUser { + #region SocketWebhookUser /// Gets the guild of this webhook. public SocketGuild Guild { get; } /// @@ -24,6 +25,8 @@ public class SocketWebhookUser : SocketUser, IWebhookUser public override ushort DiscriminatorValue { get; internal set; } /// public override string AvatarId { get; internal set; } + + /// public override bool IsBot { get; internal set; } @@ -49,9 +52,9 @@ internal static SocketWebhookUser Create(SocketGuild guild, ClientState state, M private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")}, Webhook)"; internal new SocketWebhookUser Clone() => MemberwiseClone() as SocketWebhookUser; +#endregion - - //IGuildUser + #region IGuildUser /// IGuild IGuildUser.Guild => Guild; /// @@ -63,10 +66,16 @@ internal static SocketWebhookUser Create(SocketGuild guild, ClientState state, M /// string IGuildUser.Nickname => null; /// + string IGuildUser.GuildAvatarId => null; + /// + string IGuildUser.GetGuildAvatarUrl(ImageFormat format, ushort size) => null; + /// DateTimeOffset? IGuildUser.PremiumSince => null; /// bool? IGuildUser.IsPending => null; /// + int IGuildUser.Hierarchy => 0; + /// GuildPermissions IGuildUser.GuildPermissions => GuildPermissions.Webhook; /// @@ -120,8 +129,9 @@ Task IGuildUser.RemoveRolesAsync(IEnumerable roles, RequestOptions option /// Roles are not supported on webhook users. Task IGuildUser.RemoveRolesAsync(IEnumerable roles, RequestOptions options) => throw new NotSupportedException("Roles are not supported on webhook users."); + #endregion - //IVoiceState + #region IVoiceState /// bool IVoiceState.IsDeafened => false; /// @@ -138,5 +148,8 @@ Task IGuildUser.RemoveRolesAsync(IEnumerable roles, RequestOptions option string IVoiceState.VoiceSessionId => null; /// bool IVoiceState.IsStreaming => false; + /// + DateTimeOffset? IVoiceState.RequestToSpeakTimestamp => null; + #endregion } } diff --git a/src/Discord.Net.WebSocket/Extensions/EntityExtensions.cs b/src/Discord.Net.WebSocket/Extensions/EntityExtensions.cs index cbe575075..46f5c1a26 100644 --- a/src/Discord.Net.WebSocket/Extensions/EntityExtensions.cs +++ b/src/Discord.Net.WebSocket/Extensions/EntityExtensions.cs @@ -9,7 +9,7 @@ internal static class EntityExtensions { public static IActivity ToEntity(this API.Game model) { - // Custom Status Game + #region Custom Status Game if (model.Id.IsSpecified && model.Id.Value == "custom") { return new CustomStatusGame() @@ -21,13 +21,14 @@ public static IActivity ToEntity(this API.Game model) CreatedAt = DateTimeOffset.FromUnixTimeMilliseconds(model.CreatedAt.Value), }; } + #endregion - // Spotify Game + #region Spotify Game if (model.SyncId.IsSpecified) { var assets = model.Assets.GetValueOrDefault()?.ToEntity(); string albumText = assets?[1]?.Text; - string albumArtId = assets?[1]?.ImageId?.Replace("spotify:",""); + string albumArtId = assets?[1]?.ImageId?.Replace("spotify:", ""); var timestamps = model.Timestamps.IsSpecified ? model.Timestamps.Value.ToEntity() : null; return new SpotifyGame { @@ -37,7 +38,7 @@ public static IActivity ToEntity(this API.Game model) TrackUrl = CDN.GetSpotifyDirectUrl(model.SyncId.Value), AlbumTitle = albumText, TrackTitle = model.Details.GetValueOrDefault(), - Artists = model.State.GetValueOrDefault()?.Split(';').Select(x=>x?.Trim()).ToImmutableArray(), + Artists = model.State.GetValueOrDefault()?.Split(';').Select(x => x?.Trim()).ToImmutableArray(), StartedAt = timestamps?.Start, EndsAt = timestamps?.End, Duration = timestamps?.End - timestamps?.Start, @@ -46,8 +47,9 @@ public static IActivity ToEntity(this API.Game model) Flags = model.Flags.GetValueOrDefault(), }; } + #endregion - // Rich Game + #region Rich Game if (model.ApplicationId.IsSpecified) { ulong appId = model.ApplicationId.Value; @@ -66,7 +68,9 @@ public static IActivity ToEntity(this API.Game model) Flags = model.Flags.GetValueOrDefault() }; } - // Stream Game + #endregion + + #region Stream Game if (model.StreamUrl.IsSpecified) { return new StreamingGame( @@ -77,10 +81,13 @@ public static IActivity ToEntity(this API.Game model) Details = model.Details.GetValueOrDefault() }; } - // Normal Game + #endregion + + #region Normal Game return new Game(model.Name, model.Type.GetValueOrDefault() ?? ActivityType.Playing, model.Flags.IsSpecified ? model.Flags.Value : ActivityProperties.None, model.Details.GetValueOrDefault()); + #endregion } // (Small, Large) diff --git a/src/Discord.Net.Webhook/DiscordWebhookClient.cs b/src/Discord.Net.Webhook/DiscordWebhookClient.cs index 91d077411..a4fdf9179 100644 --- a/src/Discord.Net.Webhook/DiscordWebhookClient.cs +++ b/src/Discord.Net.Webhook/DiscordWebhookClient.cs @@ -60,8 +60,7 @@ public DiscordWebhookClient(IWebhook webhook, DiscordRestConfig config) /// Thrown if the is null or whitespace. public DiscordWebhookClient(string webhookUrl, DiscordRestConfig config) : this(config) { - string token; - ParseWebhookUrl(webhookUrl, out _webhookId, out token); + ParseWebhookUrl(webhookUrl, out _webhookId, out string token); ApiClient.LoginAsync(TokenType.Webhook, token).GetAwaiter().GetResult(); Webhook = WebhookClientHelper.GetWebhookAsync(this, _webhookId).GetAwaiter().GetResult(); } @@ -88,8 +87,8 @@ private static API.DiscordRestApiClient CreateApiClient(DiscordRestConfig config /// Sends a message to the channel for this webhook. /// Returns the ID of the created message. public Task SendMessageAsync(string text = null, bool isTTS = false, IEnumerable embeds = null, - string username = null, string avatarUrl = null, RequestOptions options = null, AllowedMentions allowedMentions = null) - => WebhookClientHelper.SendMessageAsync(this, text, isTTS, embeds, username, avatarUrl, allowedMentions, options); + string username = null, string avatarUrl = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageComponent component = null) + => WebhookClientHelper.SendMessageAsync(this, text, isTTS, embeds, username, avatarUrl, allowedMentions, options, component); /// /// Modifies a message posted using this webhook. diff --git a/src/Discord.Net.Webhook/Entities/Messages/WebhookMessageProperties.cs b/src/Discord.Net.Webhook/Entities/Messages/WebhookMessageProperties.cs index dec7b6e3b..ca2ff10a0 100644 --- a/src/Discord.Net.Webhook/Entities/Messages/WebhookMessageProperties.cs +++ b/src/Discord.Net.Webhook/Entities/Messages/WebhookMessageProperties.cs @@ -22,5 +22,9 @@ public class WebhookMessageProperties /// Gets or sets the allowed mentions of the message. /// public Optional AllowedMentions { get; set; } + /// + /// Gets or sets the components that the message should display. + /// + public Optional Components { get; set; } } } diff --git a/src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs b/src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs index bbb160fcd..2a5c4786e 100644 --- a/src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs +++ b/src/Discord.Net.Webhook/Entities/Webhooks/RestInternalWebhook.cs @@ -17,6 +17,7 @@ internal class RestInternalWebhook : IWebhook public string Name { get; private set; } public string AvatarId { get; private set; } public ulong? GuildId { get; private set; } + public ulong? ApplicationId { get; private set; } public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); @@ -44,6 +45,8 @@ internal void Update(Model model) GuildId = model.GuildId.Value; if (model.Name.IsSpecified) Name = model.Name.Value; + + ApplicationId = model.ApplicationId; } public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) diff --git a/src/Discord.Net.Webhook/WebhookClientHelper.cs b/src/Discord.Net.Webhook/WebhookClientHelper.cs index 886ff234d..6e3651323 100644 --- a/src/Discord.Net.Webhook/WebhookClientHelper.cs +++ b/src/Discord.Net.Webhook/WebhookClientHelper.cs @@ -20,10 +20,15 @@ public static async Task GetWebhookAsync(DiscordWebhookClie throw new InvalidOperationException("Could not find a webhook with the supplied credentials."); return RestInternalWebhook.Create(client, model); } - public static async Task SendMessageAsync(DiscordWebhookClient client, - string text, bool isTTS, IEnumerable embeds, string username, string avatarUrl, AllowedMentions allowedMentions, RequestOptions options) + public static async Task SendMessageAsync(DiscordWebhookClient client, + string text, bool isTTS, IEnumerable embeds, string username, string avatarUrl, AllowedMentions allowedMentions, RequestOptions options, MessageComponent component) { - var args = new CreateWebhookMessageParams(text) { IsTTS = isTTS }; + var args = new CreateWebhookMessageParams + { + Content = text, + IsTTS = isTTS + }; + if (embeds != null) args.Embeds = embeds.Select(x => x.ToModel()).ToArray(); if (username != null) @@ -32,6 +37,8 @@ public static async Task SendMessageAsync(DiscordWebhookClient client, args.AvatarUrl = avatarUrl; if (allowedMentions != null) args.AllowedMentions = allowedMentions.ToModel(); + if (component != null) + args.Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray(); var model = await client.ApiClient.CreateWebhookMessageAsync(client.Webhook.Id, args, options: options).ConfigureAwait(false); return model.Id; @@ -78,7 +85,8 @@ public static async Task ModifyMessageAsync(DiscordWebhookClient client, ulong m : Optional.Create(), AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() - : Optional.Create() + : Optional.Create(), + Components = args.Components.IsSpecified ? args.Components.Value?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() : Optional.Unspecified, }; await client.ApiClient.ModifyWebhookMessageAsync(client.Webhook.Id, messageId, apiArgs, options) diff --git a/src/Discord.Net/Discord.Net.nuspec b/src/Discord.Net/Discord.Net.nuspec index e3f0150f9..cb773a379 100644 --- a/src/Discord.Net/Discord.Net.nuspec +++ b/src/Discord.Net/Discord.Net.nuspec @@ -36,4 +36,4 @@ - + \ No newline at end of file diff --git a/test/Discord.Net.Analyzers.Tests/Discord.Net.Analyzers.Tests.csproj b/test/Discord.Net.Analyzers.Tests/Discord.Net.Analyzers.Tests.csproj index 8f69672f9..1257041e4 100644 --- a/test/Discord.Net.Analyzers.Tests/Discord.Net.Analyzers.Tests.csproj +++ b/test/Discord.Net.Analyzers.Tests/Discord.Net.Analyzers.Tests.csproj @@ -15,10 +15,10 @@ - - + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/Discord.Net.Analyzers.Tests/Helpers/CodeFixVerifier.Helper.cs b/test/Discord.Net.Analyzers.Tests/Helpers/CodeFixVerifier.Helper.cs index 0f73d0643..42f7b08c1 100644 --- a/test/Discord.Net.Analyzers.Tests/Helpers/CodeFixVerifier.Helper.cs +++ b/test/Discord.Net.Analyzers.Tests/Helpers/CodeFixVerifier.Helper.cs @@ -18,7 +18,7 @@ public abstract partial class CodeFixVerifier : DiagnosticVerifier /// Apply the inputted CodeAction to the inputted document. /// Meant to be used to apply codefixes. /// - /// The Document to apply the fix on + /// The Document to apply the fix on. /// A CodeAction that will be applied to the Document. /// A Document with the changes from the CodeAction private static Document ApplyFix(Document document, CodeAction codeAction) @@ -33,8 +33,8 @@ private static Document ApplyFix(Document document, CodeAction codeAction) /// Note: Considers Diagnostics to be the same if they have the same Ids. In the case of multiple diagnostics with the same Id in a row, /// this method may not necessarily return the new one. /// - /// The Diagnostics that existed in the code before the CodeFix was applied - /// The Diagnostics that exist in the code after the CodeFix was applied + /// The Diagnostics that existed in the code before the CodeFix was applied. + /// The Diagnostics that exist in the code after the CodeFix was applied. /// A list of Diagnostics that only surfaced in the code after the CodeFix was applied private static IEnumerable GetNewDiagnostics(IEnumerable diagnostics, IEnumerable newDiagnostics) { @@ -61,7 +61,7 @@ private static IEnumerable GetNewDiagnostics(IEnumerable /// /// Get the existing compiler diagnostics on the inputted document. /// - /// The Document to run the compiler diagnostic analyzers on + /// The Document to run the compiler diagnostic analyzers on. /// The compiler diagnostics that were found in the code private static IEnumerable GetCompilerDiagnostics(Document document) { @@ -71,7 +71,7 @@ private static IEnumerable GetCompilerDiagnostics(Document document) /// /// Given a document, turn it into a string based on the syntax root /// - /// The Document to be converted to a string + /// The Document to be converted to a string. /// A string containing the syntax of the Document after formatting private static string GetStringFromDocument(Document document) { diff --git a/test/Discord.Net.Analyzers.Tests/Helpers/DiagnosticResult.cs b/test/Discord.Net.Analyzers.Tests/Helpers/DiagnosticResult.cs index 5ae6f528e..87d915494 100644 --- a/test/Discord.Net.Analyzers.Tests/Helpers/DiagnosticResult.cs +++ b/test/Discord.Net.Analyzers.Tests/Helpers/DiagnosticResult.cs @@ -20,9 +20,9 @@ public DiagnosticResultLocation(string path, int line, int column) throw new ArgumentOutOfRangeException(nameof(column), "column must be >= -1"); } - this.Path = path; - this.Line = line; - this.Column = column; + Path = path; + Line = line; + Column = column; } public string Path { get; } @@ -41,16 +41,16 @@ public DiagnosticResultLocation[] Locations { get { - if (this.locations == null) + if (locations == null) { - this.locations = new DiagnosticResultLocation[] { }; + locations = new DiagnosticResultLocation[] { }; } - return this.locations; + return locations; } set { - this.locations = value; + locations = value; } } @@ -64,7 +64,7 @@ public string Path { get { - return this.Locations.Length > 0 ? this.Locations[0].Path : ""; + return Locations.Length > 0 ? Locations[0].Path : ""; } } @@ -72,7 +72,7 @@ public int Line { get { - return this.Locations.Length > 0 ? this.Locations[0].Line : -1; + return Locations.Length > 0 ? Locations[0].Line : -1; } } @@ -80,7 +80,7 @@ public int Column { get { - return this.Locations.Length > 0 ? this.Locations[0].Column : -1; + return Locations.Length > 0 ? Locations[0].Column : -1; } } } diff --git a/test/Discord.Net.Analyzers.Tests/Helpers/DiagnosticVerifier.Helper.cs b/test/Discord.Net.Analyzers.Tests/Helpers/DiagnosticVerifier.Helper.cs index 99654f12c..23bb319a6 100644 --- a/test/Discord.Net.Analyzers.Tests/Helpers/DiagnosticVerifier.Helper.cs +++ b/test/Discord.Net.Analyzers.Tests/Helpers/DiagnosticVerifier.Helper.cs @@ -35,9 +35,9 @@ public abstract partial class DiagnosticVerifier /// /// Given classes in the form of strings, their language, and an IDiagnosticAnlayzer to apply to it, return the diagnostics found in the string after converting it to a document. /// - /// Classes in the form of strings - /// The language the source classes are in - /// The analyzer to be run on the sources + /// Classes in the form of strings. + /// The language the source classes are in. + /// The analyzer to be run on the sources. /// An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location private static Diagnostic[] GetSortedDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer) { @@ -48,8 +48,8 @@ private static Diagnostic[] GetSortedDiagnostics(string[] sources, string langua /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it. /// The returned diagnostics are then ordered by location in the source document. /// - /// The analyzer to run on the documents - /// The Documents that the analyzer will be run on + /// The analyzer to run on the documents. + /// The Documents that the analyzer will be run on. /// An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyzer analyzer, Document[] documents) { @@ -93,7 +93,7 @@ protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyz /// /// Sort diagnostics by location in source document /// - /// The list of Diagnostics to be sorted + /// The list of Diagnostics to be sorted. /// An IEnumerable containing the Diagnostics in order of Location private static Diagnostic[] SortDiagnostics(IEnumerable diagnostics) { @@ -106,8 +106,8 @@ private static Diagnostic[] SortDiagnostics(IEnumerable diagnostics) /// /// Given an array of strings as sources and a language, turn them into a project and return the documents and spans of it. /// - /// Classes in the form of strings - /// The language the source code is in + /// Classes in the form of strings. + /// The language the source code is in. /// A Tuple containing the Documents produced from the sources and their TextSpans if relevant private static Document[] GetDocuments(string[] sources, string language) { @@ -130,8 +130,8 @@ private static Document[] GetDocuments(string[] sources, string language) /// /// Create a Document from a string through creating a project that contains it. /// - /// Classes in the form of a string - /// The language the source code is in + /// Classes in the form of a string. + /// The language the source code is in. /// A Document created from the source string protected static Document CreateDocument(string source, string language = LanguageNames.CSharp) { @@ -141,8 +141,8 @@ protected static Document CreateDocument(string source, string language = Langua /// /// Create a project using the inputted strings as sources. /// - /// Classes in the form of strings - /// The language the source code is in + /// Classes in the form of strings. + /// The language the source code is in. /// A Project created out of the Documents created from the source strings private static Project CreateProject(string[] sources, string language = LanguageNames.CSharp) { @@ -187,7 +187,7 @@ private static IEnumerable Transitive(Assembly assembly) private static HashSet RecursiveReferencedAssemblies(Assembly a, HashSet assemblies = null) { - assemblies = assemblies ?? new HashSet(); + assemblies ??= new HashSet(); if (assemblies.Add(a)) { foreach (var referencedAssemblyName in a.GetReferencedAssemblies()) diff --git a/test/Discord.Net.Analyzers.Tests/Verifiers/CodeFixVerifier.cs b/test/Discord.Net.Analyzers.Tests/Verifiers/CodeFixVerifier.cs index 5d057b610..d1cb6cd1b 100644 --- a/test/Discord.Net.Analyzers.Tests/Verifiers/CodeFixVerifier.cs +++ b/test/Discord.Net.Analyzers.Tests/Verifiers/CodeFixVerifier.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; @@ -38,10 +38,10 @@ protected virtual CodeFixProvider GetBasicCodeFixProvider() /// /// Called to test a C# codefix when applied on the inputted string as a source /// - /// A class in the form of a string before the CodeFix was applied to it - /// A class in the form of a string after the CodeFix was applied to it - /// Index determining which codefix to apply if there are multiple - /// A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied + /// A class in the form of a string before the CodeFix was applied to it. + /// A class in the form of a string after the CodeFix was applied to it. + /// Index determining which codefix to apply if there are multiple. + /// A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied. protected void VerifyCSharpFix(string oldSource, string newSource, int? codeFixIndex = null, bool allowNewCompilerDiagnostics = false) { VerifyFix(LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer(), GetCSharpCodeFixProvider(), oldSource, newSource, codeFixIndex, allowNewCompilerDiagnostics); @@ -50,10 +50,10 @@ protected void VerifyCSharpFix(string oldSource, string newSource, int? codeFixI /// /// Called to test a VB codefix when applied on the inputted string as a source /// - /// A class in the form of a string before the CodeFix was applied to it - /// A class in the form of a string after the CodeFix was applied to it - /// Index determining which codefix to apply if there are multiple - /// A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied + /// A class in the form of a string before the CodeFix was applied to it. + /// A class in the form of a string after the CodeFix was applied to it. + /// Index determining which codefix to apply if there are multiple. + /// A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied. protected void VerifyBasicFix(string oldSource, string newSource, int? codeFixIndex = null, bool allowNewCompilerDiagnostics = false) { VerifyFix(LanguageNames.VisualBasic, GetBasicDiagnosticAnalyzer(), GetBasicCodeFixProvider(), oldSource, newSource, codeFixIndex, allowNewCompilerDiagnostics); @@ -65,13 +65,13 @@ protected void VerifyBasicFix(string oldSource, string newSource, int? codeFixIn /// Then gets the string after the codefix is applied and compares it with the expected result. /// Note: If any codefix causes new diagnostics to show up, the test fails unless allowNewCompilerDiagnostics is set to true. /// - /// The language the source code is in - /// The analyzer to be applied to the source code - /// The codefix to be applied to the code wherever the relevant Diagnostic is found - /// A class in the form of a string before the CodeFix was applied to it - /// A class in the form of a string after the CodeFix was applied to it - /// Index determining which codefix to apply if there are multiple - /// A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied + /// The language the source code is in. + /// The analyzer to be applied to the source code. + /// The codefix to be applied to the code wherever the relevant Diagnostic is found. + /// A class in the form of a string before the CodeFix was applied to it. + /// A class in the form of a string after the CodeFix was applied to it. + /// Index determining which codefix to apply if there are multiple. + /// A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied. private void VerifyFix(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string oldSource, string newSource, int? codeFixIndex, bool allowNewCompilerDiagnostics) { var document = CreateDocument(oldSource, language); @@ -126,4 +126,4 @@ private void VerifyFix(string language, DiagnosticAnalyzer analyzer, CodeFixProv Assert.Equal(newSource, actual); } } -} \ No newline at end of file +} diff --git a/test/Discord.Net.Analyzers.Tests/Verifiers/DiagnosticVerifier.cs b/test/Discord.Net.Analyzers.Tests/Verifiers/DiagnosticVerifier.cs index 3564093f8..9b0219a63 100644 --- a/test/Discord.Net.Analyzers.Tests/Verifiers/DiagnosticVerifier.cs +++ b/test/Discord.Net.Analyzers.Tests/Verifiers/DiagnosticVerifier.cs @@ -37,8 +37,8 @@ protected virtual DiagnosticAnalyzer GetBasicDiagnosticAnalyzer() /// Called to test a C# DiagnosticAnalyzer when applied on the single inputted string as a source /// Note: input a DiagnosticResult for each Diagnostic expected /// - /// A class in the form of a string to run the analyzer on - /// DiagnosticResults that should appear after the analyzer is run on the source + /// A class in the form of a string to run the analyzer on. + /// DiagnosticResults that should appear after the analyzer is run on the source. protected void VerifyCSharpDiagnostic(string source, params DiagnosticResult[] expected) { VerifyDiagnostics(new[] { source }, LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer(), expected); @@ -48,8 +48,8 @@ protected void VerifyCSharpDiagnostic(string source, params DiagnosticResult[] e /// Called to test a VB DiagnosticAnalyzer when applied on the single inputted string as a source /// Note: input a DiagnosticResult for each Diagnostic expected /// - /// A class in the form of a string to run the analyzer on - /// DiagnosticResults that should appear after the analyzer is run on the source + /// A class in the form of a string to run the analyzer on. + /// DiagnosticResults that should appear after the analyzer is run on the source. protected void VerifyBasicDiagnostic(string source, params DiagnosticResult[] expected) { VerifyDiagnostics(new[] { source }, LanguageNames.VisualBasic, GetBasicDiagnosticAnalyzer(), expected); @@ -59,8 +59,8 @@ protected void VerifyBasicDiagnostic(string source, params DiagnosticResult[] ex /// Called to test a C# DiagnosticAnalyzer when applied on the inputted strings as a source /// Note: input a DiagnosticResult for each Diagnostic expected /// - /// An array of strings to create source documents from to run the analyzers on - /// DiagnosticResults that should appear after the analyzer is run on the sources + /// An array of strings to create source documents from to run the analyzers on. + /// DiagnosticResults that should appear after the analyzer is run on the sources. protected void VerifyCSharpDiagnostic(string[] sources, params DiagnosticResult[] expected) { VerifyDiagnostics(sources, LanguageNames.CSharp, GetCSharpDiagnosticAnalyzer(), expected); @@ -70,8 +70,8 @@ protected void VerifyCSharpDiagnostic(string[] sources, params DiagnosticResult[ /// Called to test a VB DiagnosticAnalyzer when applied on the inputted strings as a source /// Note: input a DiagnosticResult for each Diagnostic expected /// - /// An array of strings to create source documents from to run the analyzers on - /// DiagnosticResults that should appear after the analyzer is run on the sources + /// An array of strings to create source documents from to run the analyzers on. + /// DiagnosticResults that should appear after the analyzer is run on the sources. protected void VerifyBasicDiagnostic(string[] sources, params DiagnosticResult[] expected) { VerifyDiagnostics(sources, LanguageNames.VisualBasic, GetBasicDiagnosticAnalyzer(), expected); @@ -81,10 +81,10 @@ protected void VerifyBasicDiagnostic(string[] sources, params DiagnosticResult[] /// General method that gets a collection of actual diagnostics found in the source after the analyzer is run, /// then verifies each of them. /// - /// An array of strings to create source documents from to run the analyzers on - /// The language of the classes represented by the source strings - /// The analyzer to be run on the source code - /// DiagnosticResults that should appear after the analyzer is run on the sources + /// An array of strings to create source documents from to run the analyzers on. + /// The language of the classes represented by the source strings. + /// The analyzer to be run on the source code. + /// DiagnosticResults that should appear after the analyzer is run on the sources. private void VerifyDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expected) { var diagnostics = GetSortedDiagnostics(sources, language, analyzer); @@ -98,9 +98,9 @@ private void VerifyDiagnostics(string[] sources, string language, DiagnosticAnal /// Checks each of the actual Diagnostics found and compares them with the corresponding DiagnosticResult in the array of expected results. /// Diagnostics are considered equal only if the DiagnosticResultLocation, Id, Severity, and Message of the DiagnosticResult match the actual diagnostic. /// - /// The Diagnostics found by the compiler after running the analyzer on the source code - /// The analyzer that was being run on the sources - /// Diagnostic Results that should have appeared in the code + /// The Diagnostics found by the compiler after running the analyzer on the source code. + /// The analyzer that was being run on the sources. + /// Diagnostic Results that should have appeared in the code. private static void VerifyDiagnosticResults(IEnumerable actualResults, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expectedResults) { int expectedCount = expectedResults.Length; @@ -173,10 +173,10 @@ private static void VerifyDiagnosticResults(IEnumerable actualResult /// /// Helper method to VerifyDiagnosticResult that checks the location of a diagnostic and compares it with the location in the expected DiagnosticResult. /// - /// The analyzer that was being run on the sources - /// The diagnostic that was found in the code - /// The Location of the Diagnostic found in the code - /// The DiagnosticResultLocation that should have been found + /// The analyzer that was being run on the sources. + /// The diagnostic that was found in the code. + /// The Location of the Diagnostic found in the code. + /// The DiagnosticResultLocation that should have been found. private static void VerifyDiagnosticLocation(DiagnosticAnalyzer analyzer, Diagnostic diagnostic, Location actual, DiagnosticResultLocation expected) { var actualSpan = actual.GetLineSpan(); @@ -215,8 +215,8 @@ private static void VerifyDiagnosticLocation(DiagnosticAnalyzer analyzer, Diagno /// /// Helper method to format a Diagnostic into an easily readable string /// - /// The analyzer that this verifier tests - /// The Diagnostics to be formatted + /// The analyzer that this verifier tests. + /// The Diagnostics to be formatted. /// The Diagnostics formatted as a string private static string FormatDiagnostics(DiagnosticAnalyzer analyzer, params Diagnostic[] diagnostics) { diff --git a/test/Discord.Net.Tests.Integration/ChannelsTests.cs b/test/Discord.Net.Tests.Integration/ChannelsTests.cs index 3bf60772f..9bb30c4ef 100644 --- a/test/Discord.Net.Tests.Integration/ChannelsTests.cs +++ b/test/Discord.Net.Tests.Integration/ChannelsTests.cs @@ -19,7 +19,7 @@ public class ChannelsTests : IClassFixture public ChannelsTests(RestGuildFixture guildFixture, ITestOutputHelper output) { guild = guildFixture.Guild; - this.output = output; + output = output; output.WriteLine($"RestGuildFixture using guild: {guild.Id}"); // capture all console output guildFixture.Client.Log += LogAsync; diff --git a/test/Discord.Net.Tests.Integration/Discord.Net.Tests.Integration.csproj b/test/Discord.Net.Tests.Integration/Discord.Net.Tests.Integration.csproj index c571059ef..8b16b2971 100644 --- a/test/Discord.Net.Tests.Integration/Discord.Net.Tests.Integration.csproj +++ b/test/Discord.Net.Tests.Integration/Discord.Net.Tests.Integration.csproj @@ -15,9 +15,9 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/Discord.Net.Tests.Integration/GuildTests.cs b/test/Discord.Net.Tests.Integration/GuildTests.cs index 40394a3a0..c309b0ed1 100644 --- a/test/Discord.Net.Tests.Integration/GuildTests.cs +++ b/test/Discord.Net.Tests.Integration/GuildTests.cs @@ -18,7 +18,7 @@ public GuildTests(RestGuildFixture guildFixture, ITestOutputHelper output) { client = guildFixture.Client; guild = guildFixture.Guild; - this.output = output; + output = output; output.WriteLine($"RestGuildFixture using guild: {guild.Id}"); guildFixture.Client.Log += LogAsync; } diff --git a/test/Discord.Net.Tests.Unit/ChannelPermissionsTests.cs b/test/Discord.Net.Tests.Unit/ChannelPermissionsTests.cs index a3566590a..2cab8fa21 100644 --- a/test/Discord.Net.Tests.Unit/ChannelPermissionsTests.cs +++ b/test/Discord.Net.Tests.Unit/ChannelPermissionsTests.cs @@ -85,6 +85,10 @@ void AssertFlag(Func cstr, ChannelPermission flag) AssertFlag(() => new ChannelPermissions(stream: true), ChannelPermission.Stream); AssertFlag(() => new ChannelPermissions(manageRoles: true), ChannelPermission.ManageRoles); AssertFlag(() => new ChannelPermissions(manageWebhooks: true), ChannelPermission.ManageWebhooks); + AssertFlag(() => new ChannelPermissions(useApplicationCommands: true), ChannelPermission.UseApplicationCommands); + AssertFlag(() => new ChannelPermissions(createPrivateThreads: true), ChannelPermission.CreatePrivateThreads); + AssertFlag(() => new ChannelPermissions(createPublicThreads: true), ChannelPermission.CreatePublicThreads); + AssertFlag(() => new ChannelPermissions(sendMessagesInThreads: true), ChannelPermission.SendMessagesInThreads); } /// diff --git a/test/Discord.Net.Tests.Unit/ColorTests.cs b/test/Discord.Net.Tests.Unit/ColorTests.cs index 87c76e4e2..46d8feabb 100644 --- a/test/Discord.Net.Tests.Unit/ColorTests.cs +++ b/test/Discord.Net.Tests.Unit/ColorTests.cs @@ -10,12 +10,11 @@ namespace Discord /// public class ColorTests { - [Fact] public void Color_New() { Assert.Equal(0u, new Color().RawValue); Assert.Equal(uint.MinValue, new Color(uint.MinValue).RawValue); - Assert.Equal(uint.MaxValue, new Color(uint.MaxValue).RawValue); + Assert.Throws(() => new Color(uint.MaxValue)); } [Fact] public void Color_Default() diff --git a/test/Discord.Net.Tests.Unit/Discord.Net.Tests.Unit.csproj b/test/Discord.Net.Tests.Unit/Discord.Net.Tests.Unit.csproj index 866041696..716c3ebc4 100644 --- a/test/Discord.Net.Tests.Unit/Discord.Net.Tests.Unit.csproj +++ b/test/Discord.Net.Tests.Unit/Discord.Net.Tests.Unit.csproj @@ -13,9 +13,9 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/Discord.Net.Tests.Unit/EmbedBuilderTests.cs b/test/Discord.Net.Tests.Unit/EmbedBuilderTests.cs index da21afee1..83c6ede19 100644 --- a/test/Discord.Net.Tests.Unit/EmbedBuilderTests.cs +++ b/test/Discord.Net.Tests.Unit/EmbedBuilderTests.cs @@ -9,9 +9,9 @@ namespace Discord /// public class EmbedBuilderTests { - private const string name = "chrisj"; - private const string icon = "https://meowpuffygottem.fun/blob.png"; - private const string url = "https://meowpuffygottem.fun/"; + private const string Name = "chrisj"; + private const string Icon = "https://meowpuffygottem.fun/blob.png"; + private const string Url = "https://meowpuffygottem.fun/"; /// /// Tests the behavior of . @@ -24,12 +24,12 @@ public void WithAuthor_Strings() Assert.Null(builder.Author); builder = new EmbedBuilder() - .WithAuthor(name, icon, url); + .WithAuthor(Name, Icon, Url); Assert.NotNull(builder.Author); - Assert.Equal(name, builder.Author.Name); - Assert.Equal(icon, builder.Author.IconUrl); - Assert.Equal(url, builder.Author.Url); + Assert.Equal(Name, builder.Author.Name); + Assert.Equal(Icon, builder.Author.IconUrl); + Assert.Equal(Url, builder.Author.Url); } /// @@ -39,15 +39,15 @@ public void WithAuthor_Strings() public void WithAuthor_AuthorBuilder() { var author = new EmbedAuthorBuilder() - .WithIconUrl(icon) - .WithName(name) - .WithUrl(url); + .WithIconUrl(Icon) + .WithName(Name) + .WithUrl(Url); var builder = new EmbedBuilder() .WithAuthor(author); Assert.NotNull(builder.Author); - Assert.Equal(name, builder.Author.Name); - Assert.Equal(icon, builder.Author.IconUrl); - Assert.Equal(url, builder.Author.Url); + Assert.Equal(Name, builder.Author.Name); + Assert.Equal(Icon, builder.Author.IconUrl); + Assert.Equal(Url, builder.Author.Url); } /// @@ -58,13 +58,13 @@ public void WithAuthor_ActionAuthorBuilder() { var builder = new EmbedBuilder() .WithAuthor((author) => - author.WithIconUrl(icon) - .WithName(name) - .WithUrl(url)); + author.WithIconUrl(Icon) + .WithName(Name) + .WithUrl(Url)); Assert.NotNull(builder.Author); - Assert.Equal(name, builder.Author.Name); - Assert.Equal(icon, builder.Author.IconUrl); - Assert.Equal(url, builder.Author.Url); + Assert.Equal(Name, builder.Author.Name); + Assert.Equal(Icon, builder.Author.IconUrl); + Assert.Equal(Url, builder.Author.Url); } /// @@ -74,12 +74,12 @@ public void WithAuthor_ActionAuthorBuilder() public void EmbedAuthorBuilder() { var builder = new EmbedAuthorBuilder() - .WithIconUrl(icon) - .WithName(name) - .WithUrl(url); - Assert.Equal(icon, builder.IconUrl); - Assert.Equal(name, builder.Name); - Assert.Equal(url, builder.Url); + .WithIconUrl(Icon) + .WithName(Name) + .WithUrl(Url); + Assert.Equal(Icon, builder.IconUrl); + Assert.Equal(Name, builder.Name); + Assert.Equal(Url, builder.Url); } /// @@ -95,8 +95,10 @@ public void Title_Invalid(string title) { Assert.Throws(() => { - var builder = new EmbedBuilder(); - builder.Title = title; + var builder = new EmbedBuilder + { + Title = title + }; }); Assert.Throws(() => { @@ -113,8 +115,10 @@ public void Title_Invalid(string title) [InlineData("jVyLChmA7aBZozXQuZ3VDEcwW6zOq0nteOVYBZi31ny73rpXfSSBXR4Jw6FiplDKQseKskwRMuBZkUewrewqAbkBZpslHirvC5nEzRySoDIdTRnkVvTXZUXg75l3bQCjuuHxDd6DfrY8ihd6yZX1Y0XFeg239YBcYV4TpL9uQ8H3HFYxrWhLlG2PRVjUmiglP5iXkawszNwMVm1SZ5LZT4jkMZHxFegVi7170d16iaPWOovu50aDDHy087XBtLKV")] public void Tile_Valid(string title) { - var builder = new EmbedBuilder(); - builder.Title = title; + var builder = new EmbedBuilder + { + Title = title + }; new EmbedBuilder().WithTitle(title); } @@ -133,8 +137,10 @@ IEnumerable GetInvalid() Assert.Throws(() => new EmbedBuilder().WithDescription(description)); Assert.Throws(() => { - var b = new EmbedBuilder(); - b.Description = description; + var b = new EmbedBuilder + { + Description = description + }; }); } } @@ -156,14 +162,16 @@ IEnumerable GetValid() var b = new EmbedBuilder().WithDescription(description); Assert.Equal(description, b.Description); - b = new EmbedBuilder(); - b.Description = description; + b = new EmbedBuilder + { + Description = description + }; Assert.Equal(description, b.Description); } } /// - /// Tests that valid urls do not throw any exceptions. + /// Tests that valid url's do not throw any exceptions. /// /// The url to set. [Theory] @@ -181,10 +189,12 @@ public void Url_Valid(string url) Assert.Equal(result.ImageUrl, url); Assert.Equal(result.ThumbnailUrl, url); - result = new EmbedBuilder(); - result.Url = url; - result.ImageUrl = url; - result.ThumbnailUrl = url; + result = new EmbedBuilder + { + Url = url, + ImageUrl = url, + ThumbnailUrl = url + }; Assert.Equal(result.Url, url); Assert.Equal(result.ImageUrl, url); Assert.Equal(result.ThumbnailUrl, url); @@ -207,15 +217,15 @@ public void Length_Empty() public void Length() { var e = new EmbedBuilder() - .WithAuthor(name, icon, url) + .WithAuthor(Name, Icon, Url) .WithColor(Color.Blue) .WithDescription("This is the test description.") - .WithFooter("This is the footer", url) - .WithImageUrl(url) - .WithThumbnailUrl(url) + .WithFooter("This is the footer", Url) + .WithImageUrl(Url) + .WithThumbnailUrl(Url) .WithTimestamp(DateTimeOffset.MinValue) .WithTitle("This is the title") - .WithUrl(url) + .WithUrl(Url) .AddField("Field 1", "Inline", true) .AddField("Field 2", "Not Inline", false); Assert.Equal(100, e.Length); @@ -253,11 +263,11 @@ public void WithFooter_ActionFooterBuilder() var e = new EmbedBuilder() .WithFooter(x => { - x.IconUrl = url; - x.Text = name; + x.IconUrl = Url; + x.Text = Name; }); - Assert.Equal(url, e.Footer.IconUrl); - Assert.Equal(name, e.Footer.Text); + Assert.Equal(Url, e.Footer.IconUrl); + Assert.Equal(Name, e.Footer.Text); } /// @@ -268,18 +278,20 @@ public void WithFooter_FooterBuilder() { var footer = new EmbedFooterBuilder() { - IconUrl = url, - Text = name + IconUrl = Url, + Text = Name }; var e = new EmbedBuilder() .WithFooter(footer); - Assert.Equal(url, e.Footer.IconUrl); - Assert.Equal(name, e.Footer.Text); + Assert.Equal(Url, e.Footer.IconUrl); + Assert.Equal(Name, e.Footer.Text); // use the property - e = new EmbedBuilder(); - e.Footer = footer; - Assert.Equal(url, e.Footer.IconUrl); - Assert.Equal(name, e.Footer.Text); + e = new EmbedBuilder + { + Footer = footer + }; + Assert.Equal(Url, e.Footer.IconUrl); + Assert.Equal(Name, e.Footer.Text); } /// @@ -289,9 +301,9 @@ public void WithFooter_FooterBuilder() public void WithFooter_Strings() { var e = new EmbedBuilder() - .WithFooter(name, url); - Assert.Equal(url, e.Footer.IconUrl); - Assert.Equal(name, e.Footer.Text); + .WithFooter(Name, Url); + Assert.Equal(Url, e.Footer.IconUrl); + Assert.Equal(Name, e.Footer.Text); } /// @@ -301,10 +313,10 @@ public void WithFooter_Strings() public void EmbedFooterBuilder() { var footer = new EmbedFooterBuilder() - .WithIconUrl(url) - .WithText(name); - Assert.Equal(url, footer.IconUrl); - Assert.Equal(name, footer.Text); + .WithIconUrl(Url) + .WithText(Name); + Assert.Equal(Url, footer.IconUrl); + Assert.Equal(Name, footer.Text); } /// /// Tests that invalid text throws an . @@ -375,10 +387,12 @@ public void EmbedFieldBuilder() Assert.Equal("value", e.Value); Assert.True(e.IsInline); // use the properties - e = new EmbedFieldBuilder(); - e.IsInline = true; - e.Name = "name"; - e.Value = "value"; + e = new EmbedFieldBuilder + { + IsInline = true, + Name = "name", + Value = "value" + }; Assert.Equal("name", e.Name); Assert.Equal("value", e.Value); Assert.True(e.IsInline); diff --git a/test/Discord.Net.Tests.Unit/FormatTests.cs b/test/Discord.Net.Tests.Unit/FormatTests.cs index 2a5adbaae..c015c7e15 100644 --- a/test/Discord.Net.Tests.Unit/FormatTests.cs +++ b/test/Discord.Net.Tests.Unit/FormatTests.cs @@ -59,5 +59,20 @@ public void BlockQuote(string input, string expected) { Assert.Equal(expected, Format.BlockQuote(input)); } + + [Theory] + [InlineData("", "")] + [InlineData("\n", "\n")] + [InlineData("**hi**", "hi")] + [InlineData("__uwu__", "uwu")] + [InlineData(">>__uwu__", "uwu")] + [InlineData("```uwu```", "uwu")] + [InlineData("~uwu~", "uwu")] + [InlineData("berries __and__ *Cream**, I'm a little lad who loves berries and cream", "berries and Cream, I'm a little lad who loves berries and cream")] + public void StripMarkdown(string input, string expected) + { + var test = Format.StripMarkDown(input); + Assert.Equal(expected, test); + } } } diff --git a/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs b/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs index cd29b2606..f0b0b2db7 100644 --- a/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs +++ b/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs @@ -91,7 +91,14 @@ void AssertFlag(Func cstr, GuildPermission flag) AssertFlag(() => new GuildPermissions(manageNicknames: true), GuildPermission.ManageNicknames); AssertFlag(() => new GuildPermissions(manageRoles: true), GuildPermission.ManageRoles); AssertFlag(() => new GuildPermissions(manageWebhooks: true), GuildPermission.ManageWebhooks); - AssertFlag(() => new GuildPermissions(manageEmojis: true), GuildPermission.ManageEmojis); + AssertFlag(() => new GuildPermissions(manageEmojisAndStickers: true), GuildPermission.ManageEmojisAndStickers); + AssertFlag(() => new GuildPermissions(useApplicationCommands: true), GuildPermission.UseApplicationCommands); + AssertFlag(() => new GuildPermissions(requestToSpeak: true), GuildPermission.RequestToSpeak); + AssertFlag(() => new GuildPermissions(manageEvents: true), GuildPermission.ManageEvents); + AssertFlag(() => new GuildPermissions(manageThreads: true), GuildPermission.ManageThreads); + AssertFlag(() => new GuildPermissions(createPublicThreads: true), GuildPermission.CreatePublicThreads); + AssertFlag(() => new GuildPermissions(createPrivateThreads: true), GuildPermission.CreatePrivateThreads); + AssertFlag(() => new GuildPermissions(useExternalStickers: true), GuildPermission.UseExternalStickers); } /// @@ -161,7 +168,14 @@ void AssertUtil(GuildPermission permission, AssertUtil(GuildPermission.ManageNicknames, x => x.ManageNicknames, (p, enable) => p.Modify(manageNicknames: enable)); AssertUtil(GuildPermission.ManageRoles, x => x.ManageRoles, (p, enable) => p.Modify(manageRoles: enable)); AssertUtil(GuildPermission.ManageWebhooks, x => x.ManageWebhooks, (p, enable) => p.Modify(manageWebhooks: enable)); - AssertUtil(GuildPermission.ManageEmojis, x => x.ManageEmojis, (p, enable) => p.Modify(manageEmojis: enable)); + AssertUtil(GuildPermission.ManageEmojisAndStickers, x => x.ManageEmojisAndStickers, (p, enable) => p.Modify(manageEmojisAndStickers: enable)); + AssertUtil(GuildPermission.UseApplicationCommands, x => x.UseApplicationCommands, (p, enable) => p.Modify(useApplicationCommands: enable)); + AssertUtil(GuildPermission.RequestToSpeak, x => x.RequestToSpeak, (p, enable) => p.Modify(requestToSpeak: enable)); + AssertUtil(GuildPermission.ManageEvents, x => x.ManageEvents, (p, enable) => p.Modify(manageEvents: enable)); + AssertUtil(GuildPermission.ManageThreads, x => x.ManageThreads, (p, enable) => p.Modify(manageThreads: enable)); + AssertUtil(GuildPermission.CreatePublicThreads, x => x.CreatePublicThreads, (p, enable) => p.Modify(createPublicThreads: enable)); + AssertUtil(GuildPermission.CreatePrivateThreads, x => x.CreatePrivateThreads, (p, enable) => p.Modify(createPrivateThreads: enable)); + AssertUtil(GuildPermission.UseExternalStickers, x => x.UseExternalStickers, (p, enable) => p.Modify(useExternalStickers: enable)); } } } diff --git a/test/Discord.Net.Tests.Unit/MentionUtilsTests.cs b/test/Discord.Net.Tests.Unit/MentionUtilsTests.cs index 52f35fd9c..abd1191c8 100644 --- a/test/Discord.Net.Tests.Unit/MentionUtilsTests.cs +++ b/test/Discord.Net.Tests.Unit/MentionUtilsTests.cs @@ -47,9 +47,7 @@ public void ParseUser_Pass(string user, ulong id) var parsed = MentionUtils.ParseUser(user); Assert.Equal(id, parsed); - // also check tryparse - ulong result; - Assert.True(MentionUtils.TryParseUser(user, out result)); + Assert.True(MentionUtils.TryParseUser(user, out ulong result)); Assert.Equal(id, result); } [Theory] @@ -75,9 +73,7 @@ public void ParseChannel_Pass(string channel, ulong id) var parsed = MentionUtils.ParseChannel(channel); Assert.Equal(id, parsed); - // also check tryparse - ulong result; - Assert.True(MentionUtils.TryParseChannel(channel, out result)); + Assert.True(MentionUtils.TryParseChannel(channel, out ulong result)); Assert.Equal(id, result); } [Theory] @@ -103,9 +99,7 @@ public void ParseRole_Pass(string role, ulong id) var parsed = MentionUtils.ParseRole(role); Assert.Equal(id, parsed); - // also check tryparse - ulong result; - Assert.True(MentionUtils.TryParseRole(role, out result)); + Assert.True(MentionUtils.TryParseRole(role, out ulong result)); Assert.Equal(id, result); } [Theory] diff --git a/test/Discord.Net.Tests.Unit/MockedEntities/MockedDMChannel.cs b/test/Discord.Net.Tests.Unit/MockedEntities/MockedDMChannel.cs index 593b9201a..519bab4d9 100644 --- a/test/Discord.Net.Tests.Unit/MockedEntities/MockedDMChannel.cs +++ b/test/Discord.Net.Tests.Unit/MockedEntities/MockedDMChannel.cs @@ -78,24 +78,15 @@ public IAsyncEnumerable> GetUsersAsync(CacheMode mode throw new NotImplementedException(); } - public Task SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - { - throw new NotImplementedException(); - } - - public Task SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - { - throw new NotImplementedException(); - } - - public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - { - throw new NotImplementedException(); - } - public Task TriggerTypingAsync(RequestOptions options = null) { throw new NotImplementedException(); } + + public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) => throw new NotImplementedException(); + public Task SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) => throw new NotImplementedException(); + public Task SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) => throw new NotImplementedException(); + public Task SendFileAsync(FileAttachment attachment, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) => throw new NotImplementedException(); + public Task SendFilesAsync(IEnumerable attachments, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) => throw new NotImplementedException(); } } diff --git a/test/Discord.Net.Tests.Unit/MockedEntities/MockedGroupChannel.cs b/test/Discord.Net.Tests.Unit/MockedEntities/MockedGroupChannel.cs index 6daf6a9c8..6b134d92f 100644 --- a/test/Discord.Net.Tests.Unit/MockedEntities/MockedGroupChannel.cs +++ b/test/Discord.Net.Tests.Unit/MockedEntities/MockedGroupChannel.cs @@ -86,17 +86,17 @@ public Task LeaveAsync(RequestOptions options = null) throw new NotImplementedException(); } - public Task SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) + public Task SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) { throw new NotImplementedException(); } - public Task SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) + public Task SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) { throw new NotImplementedException(); } - public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null) + public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) { throw new NotImplementedException(); } @@ -105,5 +105,8 @@ public Task TriggerTypingAsync(RequestOptions options = null) { throw new NotImplementedException(); } + + public Task SendFileAsync(FileAttachment attachment, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) => throw new NotImplementedException(); + public Task SendFilesAsync(IEnumerable attachments, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) => throw new NotImplementedException(); } } diff --git a/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs b/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs index 51aece5f2..6d08a4478 100644 --- a/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs +++ b/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs @@ -46,6 +46,10 @@ public Task CreateInviteAsync(int? maxAge = 86400, int? maxUses { throw new NotImplementedException(); } + public Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); + public Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); public Task CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null) { @@ -172,17 +176,17 @@ public Task RemovePermissionOverwriteAsync(IUser user, RequestOptions options = throw new NotImplementedException(); } - public Task SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) + public Task SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) { throw new NotImplementedException(); } - public Task SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null) + public Task SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) { throw new NotImplementedException(); } - public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null) + public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) { throw new NotImplementedException(); } @@ -206,5 +210,9 @@ IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mo { throw new NotImplementedException(); } + + public Task SendFileAsync(FileAttachment attachment, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) => throw new NotImplementedException(); + public Task SendFilesAsync(IEnumerable attachments, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) => throw new NotImplementedException(); + public Task CreateThreadAsync(string name, ThreadType type = ThreadType.PublicThread, ThreadArchiveDuration autoArchiveDuration = ThreadArchiveDuration.OneDay, IMessage message = null, bool? invitable = null, int? slowmode = null, RequestOptions options = null) => throw new NotImplementedException(); } } diff --git a/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs b/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs index 6696c3613..61a32e391 100644 --- a/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs +++ b/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs @@ -27,7 +27,6 @@ internal sealed class MockedVoiceChannel : IVoiceChannel public string Name => throw new NotImplementedException(); public DateTimeOffset CreatedAt => throw new NotImplementedException(); - public ulong Id => throw new NotImplementedException(); public Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options = null) @@ -49,6 +48,10 @@ public Task CreateInviteAsync(int? maxAge = 86400, int? maxUses { throw new NotImplementedException(); } + public Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); + public Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => throw new NotImplementedException(); public Task DeleteAsync(RequestOptions options = null) { From 900c1f4385a66fe0e190a92edf05c434b3fd5838 Mon Sep 17 00:00:00 2001 From: Quin Lynch <49576606+quinchs@users.noreply.github.com> Date: Tue, 23 Nov 2021 11:46:18 -0400 Subject: [PATCH 07/24] Fix emoto try parse (#1941) --- src/Discord.Net.Core/Entities/Emotes/Emote.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Discord.Net.Core/Entities/Emotes/Emote.cs b/src/Discord.Net.Core/Entities/Emotes/Emote.cs index cd88f97cc..3a8cd7457 100644 --- a/src/Discord.Net.Core/Entities/Emotes/Emote.cs +++ b/src/Discord.Net.Core/Entities/Emotes/Emote.cs @@ -74,6 +74,10 @@ public static Emote Parse(string text) public static bool TryParse(string text, out Emote result) { result = null; + + if (text == null) + return false; + if (text.Length >= 4 && text[0] == '<' && (text[1] == ':' || (text[1] == 'a' && text[2] == ':')) && text[text.Length - 1] == '>') { bool animated = text[1] == 'a'; From 3cb662ff7a829c0d436be5437a921da7927e38aa Mon Sep 17 00:00:00 2001 From: d4n Date: Tue, 23 Nov 2021 10:49:31 -0500 Subject: [PATCH 08/24] Add null check to AllowedMentions.ToModel() (#1865) --- src/Discord.Net.Rest/Extensions/EntityExtensions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Discord.Net.Rest/Extensions/EntityExtensions.cs b/src/Discord.Net.Rest/Extensions/EntityExtensions.cs index 61fe330df..9e1e5102f 100644 --- a/src/Discord.Net.Rest/Extensions/EntityExtensions.cs +++ b/src/Discord.Net.Rest/Extensions/EntityExtensions.cs @@ -71,6 +71,7 @@ public static API.Embed ToModel(this Embed entity) public static API.AllowedMentions ToModel(this AllowedMentions entity) { + if (entity == null) return null; return new API.AllowedMentions() { Parse = entity.AllowedTypes?.EnumerateMentionTypes().ToArray(), From e0dbe7c69543d9fcdf24c26e9c16c9b8b1eaa94d Mon Sep 17 00:00:00 2001 From: Paulo Date: Wed, 24 Nov 2021 09:43:57 -0300 Subject: [PATCH 09/24] Add MaxBitrate to the interface (#1861) Co-authored-by: Quin Lynch <49576606+quinchs@users.noreply.github.com> --- src/Discord.Net.Core/Entities/Guilds/IGuild.cs | 7 +++++++ src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs | 14 ++++++++++++++ .../Entities/Guilds/SocketGuild.cs | 10 ++-------- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs index ebf2ccd4a..c2db435cf 100644 --- a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs +++ b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs @@ -313,6 +313,13 @@ public interface IGuild : IDeletable, ISnowflakeEntity /// The approximate number of non-offline members in this guild. /// int? ApproximatePresenceCount { get; } + /// + /// Gets the max bitrate for voice channels in this guild. + /// + /// + /// A representing the maximum bitrate value allowed by Discord in this guild. + /// + int MaxBitrate { get; } /// /// Gets the preferred locale of this guild in IETF BCP 47 diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs index 9b0b66633..daecb1d8c 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs @@ -85,6 +85,20 @@ public class RestGuild : RestEntity, IGuild, IUpdateable public int? ApproximateMemberCount { get; private set; } /// public int? ApproximatePresenceCount { get; private set; } + /// + public int MaxBitrate + { + get + { + return PremiumTier switch + { + PremiumTier.Tier1 => 128000, + PremiumTier.Tier2 => 256000, + PremiumTier.Tier3 => 384000, + _ => 96000, + }; + } + } /// public NsfwLevel NsfwLevel { get; private set; } /// diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs index beaab1cfe..03c655a34 100644 --- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -185,24 +185,18 @@ public SocketVoiceChannel AFKChannel return id.HasValue ? GetVoiceChannel(id.Value) : null; } } - /// - /// Gets the max bitrate for voice channels in this guild. - /// - /// - /// A representing the maximum bitrate value allowed by Discord in this guild. - /// + /// public int MaxBitrate { get { - var maxBitrate = PremiumTier switch + return PremiumTier switch { PremiumTier.Tier1 => 128000, PremiumTier.Tier2 => 256000, PremiumTier.Tier3 => 384000, _ => 96000, }; - return maxBitrate; } } /// From 6abdfcbf878329f8294884b60e90acf797bf1f9b Mon Sep 17 00:00:00 2001 From: Slate Date: Wed, 24 Nov 2021 12:55:07 +0000 Subject: [PATCH 10/24] Added negative TimeSpan handling (#1666) - Added unit tests for the TimeSpanTypeReader - Fixes https://github.com/discord-net/Discord.Net/issues/1657 --- .../Readers/TimeSpanTypeReader.cs | 58 ++++++++++----- .../TimeSpanTypeReaderTests.cs | 70 +++++++++++++++++++ 2 files changed, 109 insertions(+), 19 deletions(-) create mode 100644 test/Discord.Net.Tests.Unit/TimeSpanTypeReaderTests.cs diff --git a/src/Discord.Net.Commands/Readers/TimeSpanTypeReader.cs b/src/Discord.Net.Commands/Readers/TimeSpanTypeReader.cs index b4a27cb5b..5448553b3 100644 --- a/src/Discord.Net.Commands/Readers/TimeSpanTypeReader.cs +++ b/src/Discord.Net.Commands/Readers/TimeSpanTypeReader.cs @@ -6,30 +6,50 @@ namespace Discord.Commands { internal class TimeSpanTypeReader : TypeReader { - private static readonly string[] Formats = { - "%d'd'%h'h'%m'm'%s's'", //4d3h2m1s - "%d'd'%h'h'%m'm'", //4d3h2m - "%d'd'%h'h'%s's'", //4d3h 1s - "%d'd'%h'h'", //4d3h - "%d'd'%m'm'%s's'", //4d 2m1s - "%d'd'%m'm'", //4d 2m - "%d'd'%s's'", //4d 1s - "%d'd'", //4d - "%h'h'%m'm'%s's'", // 3h2m1s - "%h'h'%m'm'", // 3h2m - "%h'h'%s's'", // 3h 1s - "%h'h'", // 3h - "%m'm'%s's'", // 2m1s - "%m'm'", // 2m - "%s's'", // 1s + /// + /// TimeSpan try parse formats. + /// + private static readonly string[] Formats = + { + "%d'd'%h'h'%m'm'%s's'", // 4d3h2m1s + "%d'd'%h'h'%m'm'", // 4d3h2m + "%d'd'%h'h'%s's'", // 4d3h 1s + "%d'd'%h'h'", // 4d3h + "%d'd'%m'm'%s's'", // 4d 2m1s + "%d'd'%m'm'", // 4d 2m + "%d'd'%s's'", // 4d 1s + "%d'd'", // 4d + "%h'h'%m'm'%s's'", // 3h2m1s + "%h'h'%m'm'", // 3h2m + "%h'h'%s's'", // 3h 1s + "%h'h'", // 3h + "%m'm'%s's'", // 2m1s + "%m'm'", // 2m + "%s's'", // 1s }; /// public override Task ReadAsync(ICommandContext context, string input, IServiceProvider services) { - return (TimeSpan.TryParseExact(input.ToLowerInvariant(), Formats, CultureInfo.InvariantCulture, out var timeSpan)) - ? Task.FromResult(TypeReaderResult.FromSuccess(timeSpan)) - : Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse TimeSpan")); + if (string.IsNullOrEmpty(input)) + throw new ArgumentException(message: $"{nameof(input)} must not be null or empty.", paramName: nameof(input)); + + var isNegative = input[0] == '-'; // Char for CultureInfo.InvariantCulture.NumberFormat.NegativeSign + if (isNegative) + { + input = input.Substring(1); + } + + if (TimeSpan.TryParseExact(input.ToLowerInvariant(), Formats, CultureInfo.InvariantCulture, out var timeSpan)) + { + return isNegative + ? Task.FromResult(TypeReaderResult.FromSuccess(-timeSpan)) + : Task.FromResult(TypeReaderResult.FromSuccess(timeSpan)); + } + else + { + return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse TimeSpan")); + } } } } diff --git a/test/Discord.Net.Tests.Unit/TimeSpanTypeReaderTests.cs b/test/Discord.Net.Tests.Unit/TimeSpanTypeReaderTests.cs new file mode 100644 index 000000000..4cd9cae09 --- /dev/null +++ b/test/Discord.Net.Tests.Unit/TimeSpanTypeReaderTests.cs @@ -0,0 +1,70 @@ +using Discord.Commands; +using System; +using Xunit; + +namespace Discord +{ + public class TimeSpanTypeReaderTests + { + [Theory] + [InlineData("4d3h2m1s", false)] // tests format "%d'd'%h'h'%m'm'%s's'" + [InlineData("4d3h2m", false)] // tests format "%d'd'%h'h'%m'm'" + [InlineData("4d3h1s", false)] // tests format "%d'd'%h'h'%s's'" + [InlineData("4d3h", false)] // tests format "%d'd'%h'h'" + [InlineData("4d2m1s", false)] // tests format "%d'd'%m'm'%s's'" + [InlineData("4d2m", false)] // tests format "%d'd'%m'm'" + [InlineData("4d1s", false)] // tests format "%d'd'%s's'" + [InlineData("4d", false)] // tests format "%d'd'" + [InlineData("3h2m1s", false)] // tests format "%h'h'%m'm'%s's'" + [InlineData("3h2m", false)] // tests format "%h'h'%m'm'" + [InlineData("3h1s", false)] // tests format "%h'h'%s's'" + [InlineData("3h", false)] // tests format "%h'h'" + [InlineData("2m1s", false)] // tests format "%m'm'%s's'" + [InlineData("2m", false)] // tests format "%m'm'" + [InlineData("1s", false)] // tests format "%s's'" + // Negatives + [InlineData("-4d3h2m1s", true)] // tests format "-%d'd'%h'h'%m'm'%s's'" + [InlineData("-4d3h2m", true)] // tests format "-%d'd'%h'h'%m'm'" + [InlineData("-4d3h1s", true)] // tests format "-%d'd'%h'h'%s's'" + [InlineData("-4d3h", true)] // tests format "-%d'd'%h'h'" + [InlineData("-4d2m1s", true)] // tests format "-%d'd'%m'm'%s's'" + [InlineData("-4d2m", true)] // tests format "-%d'd'%m'm'" + [InlineData("-4d1s", true)] // tests format "-%d'd'%s's'" + [InlineData("-4d", true)] // tests format "-%d'd'" + [InlineData("-3h2m1s", true)] // tests format "-%h'h'%m'm'%s's'" + [InlineData("-3h2m", true)] // tests format "-%h'h'%m'm'" + [InlineData("-3h1s", true)] // tests format "-%h'h'%s's'" + [InlineData("-3h", true)] // tests format "-%h'h'" + [InlineData("-2m1s", true)] // tests format "-%m'm'%s's'" + [InlineData("-2m", true)] // tests format "-%m'm'" + [InlineData("-1s", true)] // tests format "-%s's'" + public void TestTimeSpanParse(string input, bool isNegative) + { + var reader = new TimeSpanTypeReader(); + var result = reader.ReadAsync(null, input, null).Result; + Assert.True(result.IsSuccess); + + var actual = (TimeSpan)result.BestMatch; + Assert.True(actual != TimeSpan.Zero); + + if (isNegative) + { + Assert.True(actual < TimeSpan.Zero); + + Assert.True(actual.Seconds == 0 || actual.Seconds == -1); + Assert.True(actual.Minutes == 0 || actual.Minutes == -2); + Assert.True(actual.Hours == 0 || actual.Hours == -3); + Assert.True(actual.Days == 0 || actual.Days == -4); + } + else + { + Assert.True(actual > TimeSpan.Zero); + + Assert.True(actual.Seconds == 0 || actual.Seconds == 1); + Assert.True(actual.Minutes == 0 || actual.Minutes == 2); + Assert.True(actual.Hours == 0 || actual.Hours == 3); + Assert.True(actual.Days == 0 || actual.Days == 4); + } + } + } +} From f7a07aec02658cd289f283bb1e992d511ed9f5c1 Mon Sep 17 00:00:00 2001 From: Paulo Date: Wed, 24 Nov 2021 09:57:06 -0300 Subject: [PATCH 11/24] Add default nullable enum typereader (#1518) --- src/Discord.Net.Commands/CommandService.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index db08d0d79..bd65b0eb7 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -438,6 +438,13 @@ internal TypeReader GetDefaultTypeReader(Type type) _defaultTypeReaders[type] = reader; return reader; } + var underlyingType = Nullable.GetUnderlyingType(type); + if (underlyingType != null && underlyingType.IsEnum) + { + reader = NullableTypeReader.Create(underlyingType, EnumTypeReader.GetReader(underlyingType)); + _defaultTypeReaders[type] = reader; + return reader; + } //Is this an entity? for (int i = 0; i < _entityTypeReaders.Count; i++) From bc440abd445d58aa5bbe2c8f551c43d54aecbdc8 Mon Sep 17 00:00:00 2001 From: Quin Lynch <49576606+quinchs@users.noreply.github.com> Date: Wed, 24 Nov 2021 12:52:55 -0400 Subject: [PATCH 12/24] Implement multi-file upload to webhooks (#1942) --- .../API/Rest/UploadWebhookFileParams.cs | 38 +++++++++---- .../DiscordWebhookClient.cs | 29 ++++++++-- .../WebhookClientHelper.cs | 53 ++++++++++++++----- 3 files changed, 92 insertions(+), 28 deletions(-) diff --git a/src/Discord.Net.Rest/API/Rest/UploadWebhookFileParams.cs b/src/Discord.Net.Rest/API/Rest/UploadWebhookFileParams.cs index d925e0108..3d09ad145 100644 --- a/src/Discord.Net.Rest/API/Rest/UploadWebhookFileParams.cs +++ b/src/Discord.Net.Rest/API/Rest/UploadWebhookFileParams.cs @@ -11,9 +11,8 @@ internal class UploadWebhookFileParams { private static JsonSerializer _serializer = new JsonSerializer { ContractResolver = new DiscordContractResolver() }; - public Stream File { get; } + public FileAttachment[] Files { get; } - public Optional Filename { get; set; } public Optional Content { get; set; } public Optional Nonce { get; set; } public Optional IsTTS { get; set; } @@ -21,22 +20,16 @@ internal class UploadWebhookFileParams public Optional AvatarUrl { get; set; } public Optional Embeds { get; set; } public Optional AllowedMentions { get; set; } + public Optional MessageComponents { get; set; } - public bool IsSpoiler { get; set; } = false; - - public UploadWebhookFileParams(Stream file) + public UploadWebhookFileParams(params FileAttachment[] files) { - File = file; + Files = files; } public IReadOnlyDictionary ToDictionary() { var d = new Dictionary(); - var filename = Filename.GetValueOrDefault("unknown.dat"); - if (IsSpoiler && !filename.StartsWith(AttachmentExtensions.SpoilerPrefix)) - filename = filename.Insert(0, AttachmentExtensions.SpoilerPrefix); - - d["file"] = new MultipartFile(File, filename); var payload = new Dictionary(); if (Content.IsSpecified) @@ -49,11 +42,34 @@ public IReadOnlyDictionary ToDictionary() payload["username"] = Username.Value; if (AvatarUrl.IsSpecified) payload["avatar_url"] = AvatarUrl.Value; + if (MessageComponents.IsSpecified) + payload["components"] = MessageComponents.Value; if (Embeds.IsSpecified) payload["embeds"] = Embeds.Value; if (AllowedMentions.IsSpecified) payload["allowed_mentions"] = AllowedMentions.Value; + List attachments = new(); + + for (int n = 0; n != Files.Length; n++) + { + var attachment = Files[n]; + + var filename = attachment.FileName ?? "unknown.dat"; + if (attachment.IsSpoiler && !filename.StartsWith(AttachmentExtensions.SpoilerPrefix)) + filename = filename.Insert(0, AttachmentExtensions.SpoilerPrefix); + d[$"files[{n}]"] = new MultipartFile(attachment.Stream, filename); + + attachments.Add(new + { + id = (ulong)n, + filename = filename, + description = attachment.Description ?? Optional.Unspecified + }); + } + + payload["attachments"] = attachments; + var json = new StringBuilder(); using (var text = new StringWriter(json)) using (var writer = new JsonTextWriter(text)) diff --git a/src/Discord.Net.Webhook/DiscordWebhookClient.cs b/src/Discord.Net.Webhook/DiscordWebhookClient.cs index a4fdf9179..f7ad7301c 100644 --- a/src/Discord.Net.Webhook/DiscordWebhookClient.cs +++ b/src/Discord.Net.Webhook/DiscordWebhookClient.cs @@ -123,14 +123,35 @@ public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null) /// Returns the ID of the created message. public Task SendFileAsync(string filePath, string text, bool isTTS = false, IEnumerable embeds = null, string username = null, string avatarUrl = null, - RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null) - => WebhookClientHelper.SendFileAsync(this, filePath, text, isTTS, embeds, username, avatarUrl, allowedMentions, options, isSpoiler); + RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, + MessageComponent components = null) + => WebhookClientHelper.SendFileAsync(this, filePath, text, isTTS, embeds, username, avatarUrl, + allowedMentions, options, isSpoiler, components); /// Sends a message to the channel for this webhook with an attachment. /// Returns the ID of the created message. public Task SendFileAsync(Stream stream, string filename, string text, bool isTTS = false, IEnumerable embeds = null, string username = null, string avatarUrl = null, - RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null) - => WebhookClientHelper.SendFileAsync(this, stream, filename, text, isTTS, embeds, username, avatarUrl, allowedMentions, options, isSpoiler); + RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, + MessageComponent components = null) + => WebhookClientHelper.SendFileAsync(this, stream, filename, text, isTTS, embeds, username, + avatarUrl, allowedMentions, options, isSpoiler, components); + + /// Sends a message to the channel for this webhook with an attachment. + /// Returns the ID of the created message. + public Task SendFileAsync(FileAttachment attachment, string text, bool isTTS = false, + IEnumerable embeds = null, string username = null, string avatarUrl = null, + RequestOptions options = null, AllowedMentions allowedMentions = null, MessageComponent components = null) + => WebhookClientHelper.SendFileAsync(this, attachment, text, isTTS, embeds, username, + avatarUrl, allowedMentions, components, options); + + /// Sends a message to the channel for this webhook with an attachment. + /// Returns the ID of the created message. + public Task SendFilesAsync(IEnumerable attachments, string text, bool isTTS = false, + IEnumerable embeds = null, string username = null, string avatarUrl = null, + RequestOptions options = null, AllowedMentions allowedMentions = null, MessageComponent components = null) + => WebhookClientHelper.SendFilesAsync(this, attachments, text, isTTS, embeds, username, avatarUrl, + allowedMentions, components, options); + /// Modifies the properties of this webhook. public Task ModifyWebhookAsync(Action func, RequestOptions options = null) diff --git a/src/Discord.Net.Webhook/WebhookClientHelper.cs b/src/Discord.Net.Webhook/WebhookClientHelper.cs index 6e3651323..8b4bb5d2a 100644 --- a/src/Discord.Net.Webhook/WebhookClientHelper.cs +++ b/src/Discord.Net.Webhook/WebhookClientHelper.cs @@ -97,24 +97,51 @@ public static async Task DeleteMessageAsync(DiscordWebhookClient client, ulong m await client.ApiClient.DeleteWebhookMessageAsync(client.Webhook.Id, messageId, options).ConfigureAwait(false); } public static async Task SendFileAsync(DiscordWebhookClient client, string filePath, string text, bool isTTS, - IEnumerable embeds, string username, string avatarUrl, AllowedMentions allowedMentions, RequestOptions options, bool isSpoiler) + IEnumerable embeds, string username, string avatarUrl, AllowedMentions allowedMentions, RequestOptions options, bool isSpoiler, MessageComponent components) { string filename = Path.GetFileName(filePath); using (var file = File.OpenRead(filePath)) - return await SendFileAsync(client, file, filename, text, isTTS, embeds, username, avatarUrl, allowedMentions, options, isSpoiler).ConfigureAwait(false); + return await SendFileAsync(client, file, filename, text, isTTS, embeds, username, avatarUrl, allowedMentions, options, isSpoiler, components).ConfigureAwait(false); } - public static async Task SendFileAsync(DiscordWebhookClient client, Stream stream, string filename, string text, bool isTTS, - IEnumerable embeds, string username, string avatarUrl, AllowedMentions allowedMentions, RequestOptions options, bool isSpoiler) + public static Task SendFileAsync(DiscordWebhookClient client, Stream stream, string filename, string text, bool isTTS, + IEnumerable embeds, string username, string avatarUrl, AllowedMentions allowedMentions, RequestOptions options, bool isSpoiler, + MessageComponent components) + => SendFileAsync(client, new FileAttachment(stream, filename, isSpoiler: isSpoiler), text, isTTS, embeds, username, avatarUrl, allowedMentions, components, options); + + public static Task SendFileAsync(DiscordWebhookClient client, FileAttachment attachment, string text, bool isTTS, IEnumerable embeds, string username, string avatarUrl, AllowedMentions allowedMentions, MessageComponent components, RequestOptions options) + => SendFilesAsync(client, new FileAttachment[] { attachment }, text, isTTS, embeds, username, avatarUrl, allowedMentions, components, options); + + public static async Task SendFilesAsync(DiscordWebhookClient client, + IEnumerable attachments, string text, bool isTTS, IEnumerable embeds, string username, string avatarUrl, AllowedMentions allowedMentions, MessageComponent components, RequestOptions options) { - var args = new UploadWebhookFileParams(stream) { Filename = filename, Content = text, IsTTS = isTTS, IsSpoiler = isSpoiler }; - if (username != null) - args.Username = username; - if (avatarUrl != null) - args.AvatarUrl = avatarUrl; - if (embeds != null) - args.Embeds = embeds.Select(x => x.ToModel()).ToArray(); - if(allowedMentions != null) - args.AllowedMentions = allowedMentions.ToModel(); + embeds ??= Array.Empty(); + + Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed."); + Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed."); + Preconditions.AtMost(embeds.Count(), 10, nameof(embeds), "A max of 10 embeds are allowed."); + + foreach (var attachment in attachments) + { + Preconditions.NotNullOrEmpty(attachment.FileName, nameof(attachment.FileName), "File Name must not be empty or null"); + } + + // check that user flag and user Id list are exclusive, same with role flag and role Id list + if (allowedMentions != null && allowedMentions.AllowedTypes.HasValue) + { + if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Users) && + allowedMentions.UserIds != null && allowedMentions.UserIds.Count > 0) + { + throw new ArgumentException("The Users flag is mutually exclusive with the list of User Ids.", nameof(allowedMentions)); + } + + if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Roles) && + allowedMentions.RoleIds != null && allowedMentions.RoleIds.Count > 0) + { + throw new ArgumentException("The Roles flag is mutually exclusive with the list of Role Ids.", nameof(allowedMentions)); + } + } + + var args = new UploadWebhookFileParams(attachments.ToArray()) {AvatarUrl = avatarUrl, Username = username, Content = text, IsTTS = isTTS, Embeds = embeds.Any() ? embeds.Select(x => x.ToModel()).ToArray() : Optional.Unspecified, AllowedMentions = allowedMentions?.ToModel() ?? Optional.Unspecified, MessageComponents = components?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional.Unspecified }; var msg = await client.ApiClient.UploadWebhookFileAsync(client.Webhook.Id, args, options).ConfigureAwait(false); return msg.Id; } From b5c150dc166f288ab4a400097259a1ecda5ce399 Mon Sep 17 00:00:00 2001 From: Quin Lynch <49576606+quinchs@users.noreply.github.com> Date: Wed, 24 Nov 2021 12:53:39 -0400 Subject: [PATCH 13/24] Add Voice binaries (#1944) * Add binaries and read me * Update sending voice docs * Undo markdown formatting --- docs/guides/voice/sending-voice.md | 2 +- voice-natives/README.md | 12 ++++++++++++ voice-natives/vnext_natives_win32_x64.zip | Bin 0 -> 451429 bytes voice-natives/vnext_natives_win32_x86.zip | Bin 0 -> 411626 bytes 4 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 voice-natives/README.md create mode 100644 voice-natives/vnext_natives_win32_x64.zip create mode 100644 voice-natives/vnext_natives_win32_x86.zip diff --git a/docs/guides/voice/sending-voice.md b/docs/guides/voice/sending-voice.md index 476f2f42e..555adbca2 100644 --- a/docs/guides/voice/sending-voice.md +++ b/docs/guides/voice/sending-voice.md @@ -18,7 +18,7 @@ when developing on .NET Core, this is where you execute `dotnet run` from; typically the same directory as your csproj). For Windows Users, precompiled binaries are available for your -convienence [here](https://discord.foxbot.me/binaries/). +convienence [here](https://github.com/discord-net/Discord.Net/tree/dev/voice-natives). For Linux Users, you will need to compile [Sodium] and [Opus] from source, or install them from your package manager. diff --git a/voice-natives/README.md b/voice-natives/README.md new file mode 100644 index 000000000..a89fad45f --- /dev/null +++ b/voice-natives/README.md @@ -0,0 +1,12 @@ +# Voice binaries + +These binaries were taken from the [DSharpPlus](https://dsharpplus.github.io/natives/index.html) website and are temporary until we resolve the old url for them. + +**NOTE**: You need to rename libopus.dll to opus.dll before use, otherwise audio client will complain about missing libraries. + +#### Licenses + +| Library | License | +| :-------: | :-------------------------------------------------------- | +| Opus | https://opus-codec.org/license/ | +| libsodium | https://github.com/jedisct1/libsodium/blob/master/LICENSE | diff --git a/voice-natives/vnext_natives_win32_x64.zip b/voice-natives/vnext_natives_win32_x64.zip new file mode 100644 index 0000000000000000000000000000000000000000..a447803e52d17acb2488e88f9f954ae66acb3f22 GIT binary patch literal 451429 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�ttf!a2WT4^+xkp>KNy z-ItgE;ydg>bK?~B*Po`(80BM=OF5a?B?9lh%b@sq6Y#dvqW#78*tC2b^}o6a<@Qg( z?ZjWuBc(3#k>la2tukkJTb@dn8(-Ml6oZo4J zd@0lnUjrY<7tlHxK`uo!WAb|*SZApShkm#d8BrJ1`}GHzim-rM{cO6Q#|BD<{b*}L zHLi7^r3&m%@xZT17;ZHmcJ91MKX>@xZ?#QebW9woFT6sx?0<@)X&-SQF0_*3gU7MCr~cH|T6!1F;V-<1x|q$f$aPR`*)EqrnW~IC=3wW*aOxbO0j0oQ0;@ z5BO`_T|CV;O@DN3gljTB)*x zOBKiUKrb%@lYJbK=iLk9Qo9&IeKj?h<_D3Pi`e7Ug6w%&bZK}we3FmHMU!!87RQD= z_aIC%0(WaKRRI>6F<{ft2Rlmz@VkBoDom@eJ~b29aOHx993L3yvqF-E9Olv;WbhRm z{vt!kIpwVw{cM!(jT6SwFDIa-DHM#C3D6DBdSI<9fjJxs$ofMH=eog8rbupJB^F@$Etd$@3f1M|-AfbDZ%!Xv>Xs=E0D1}r>B-cN5t=}33tP+EgI zb-oZZPX(IS8^L_*1u#F`o!q#U27BZKK+jnRt@%vIiO~w|nH7PIo;7&#WEtA-@B(KJ za~SGv!TWj7iEe5e@{hMeZg?y>?)n0iDKoGnKnC7er$Xq5F6f`v03W3jFklHgei2xX za$+2Ca%L%&UNC|8+C%8#gBRcd;~w^017KnYwBf`Xc#_uu@unppa!{E%v0Fl4`xrwn z?!e56_aq~_6QH8F>RXk!sXd_cER}y8#P#jzZnX<*;9r4NE+^@m{zsC=|RS3wN49 zcX}jDsHB4I1!sC~=^1!BYDPOQvV)4D0y*B14_ouLqEu}Ps(&~^ciy#upJ4?gspt?) zO!L67L=l|yJPwQJD}#niA|BqY2=5;L22L-@fu+a9a4Ekye#T^S#mgOiizRSZ&t6#h z@))@BwP9kySsY=%0xrp1Ah*{V2_y*DPUjhM^&y9`!!Nk5@2YgT1k!{}^P@PwigztR-_P&C|L-iSkK3hhu@D*xq5W!Ft z4;-KK6w(GbVYkLGSZUSbuBT1pj-U{D)LNpeMFS|`A1Crvhe1AB92>POfj1nB;^Ux|xX{t6v?3y^meCnJW0IW)UIrC%gNU}=>jZQv?|69uB+Yubh{ zbP5QYkrW7=ZlfwIn^4y%2&(2}fLrE1Mr`#!NNMe*X`G$tKVeP+bb_IvdMj-cEC9`*Lp8haE4L3~|2 z-5|vezYMM>&kl#d5{cK)?N$$SevAW;J<5UBkx8`u zXEqug?t_W#8)2TzQcApfu*lvXW);jqqD~dfEqowyC<>LF=EHrnAzaUBXT0CRNiE*T z!u92A$a$AQ6q0^JvR<4<@1l0Rb1WTB$Gsu^U6$ydBu89#J%fDz0CN4sZ{X=8Te4=I z5kxQdA&(}*@MK>fP4#VrOYTS_7wv(%Fe?mgPR0y+pXv&Hg$3QdbbhA+Jm%j|gLNNa zpH2z=V*dz&g?>XX2)zIksz%=Le~ry)2ITQ3S6EbCLeJ|jgqSe{>^yTES1B%|^+7GL zw=fISdfA}o$N_q7Pa4|vOp)>YD8`^Dal8?|nb8^D68i%;p_cS<)OU`-#AzicOBRF= zniuI}!4Ek0mK#szOXF`gxR9<^UO2&?PWIey1C}3qaPgP*(EV5vBro%Wkc3FNdKjq9*MMvE4+L(YxjKEAU#O@g6^SV zh8Jl)&5KvwXA=zD2CD_uPgl{3L#nP}dDvcf~YsQ80KG4xEfvvpl z)Pp?`KGa6w>+4?ldDB*0AL9h6RS!wBpe71d>;uaajrfB{niPk8gzdTfG^gzEznzsHk!gXF7_3V@^jI!&aap*P3X43arj>M9ajnk z;^QlqAw!rz?4E$yYlx;7Mk78jGVI|5-i zNda3s%}`8Hf=27KKY0(|g1IT&Yyr(Ri;$oIe!F*;!j~+VyYV<2 z{H-! z_-i>nawx*1v0E|DeiezYW5o4tR6>;i$?SB-c;l83hGYv&*E}IX&QN+77=q zS-}fT_~1u) zFkMHFzm0*DoAU5lh%sY+rt|dE=oFkN31qZKh4GNtdTMg?9EA2x5tGnBl(FfcWgA8D z?e%IJAZdsOL#t@p+!RRAaiq)UN#lbfnJCLK3ZedPq+5#x-JG+iUd0jI+nY^()1L?L z`s+bApbKZG#7KMDGgwd^NrO!)@y0C$y3+Mmc&)O7o+LZq@-|5rJ+uyIIX(jC3Nf_V zp9d!vtw6yCAu!;ZkM4KgpvvcO`0Z9dof46Qn{F3z<0lOau#u&n*`J}&tBDM9KY$au zH|TAL)9@{47k*lH7}vW!fPjt$}C-t_Mz8 zO25$wyndz{L;S?C;9xOCZEl8W4jHspn+I~q0w_6l3F4l6k@frZP;BuY8hxoAonH6j z<(rC-Q7B251+t<*uQ+M0u*SgP4}`zX1A|uvQ)z~sK*P-(W7}oX#lQ$9_~t?0R!g#O z(izfDFk%U>{EG3f89AS%uFDrIJhg4y=uq;%k>7#M468Y^<2PoYA z94|bn0hKqrxHx?uaC2J2wXSZsGZ*OmbF+A^@eR3i!WkB1_(CCXH%9PP(Iu7|VBmL< z=yYEH>1b^EY0aSCo0 z1>s<%HWaL=BGWV4(8l9V7S?-0!h&x!x9=Ae_$-b;w@6{A(tga{#?;d8h^f= zh643#AZQ+pi@MU#;e-(3IpUA&+52$vM;sW7>5}o5a;)hrB?+v4kl>I9@AZnX``#N6 z7nj55#hYMt$rKvhA-FBr5tSevou{;LvtcYO3?0PkXik#lT?TW6lgXuuI&9yhgCd-# z!EAm%sqg#&AFi5`3l&eGGk-hvi#NjP)Afut3W51|ZOMyw$@t)zF7SkG!4J-oi1w4% zM)S#sDr=axB!%*sa6!BT!=_fJ4w1U@5cpjL)$J%9obv$h8u*g#xdi7P(ZX_Vb@Y`y z4T_;FvEL(uHbtz(lO}njBJeEgx^`nH{{&7)@xW%<4^I|^kTJ~}TyX3tvP5fOM@J!f z%{PLx7gpinUyaf1NDe)K?r`+P2NbX>g6U(m5M9^ADAQu-0TBh9Uv&tC7!0+IeIoBF zZeX4KAoXU{quO7MU9q4z?>J`Q^9;u(d7#;RTkUwCom@IMs>U zxjAsamIGXMj#51tIpEs&lBBzYA!ms=-9IlIr=kiI%VHVD>2>}ITO{!v2h}q^_ zQPKSwDr(C^zNibl8TpCU)(o4DG}2ES_5fGoKClUmg3WGoXrpKpxMzC6rX~wK-uM{> zSp`up%NtU*Z^1?PeaJ;mdCW>M2mfDA;Faoiz;|c?e&F<=w+^@h!`49`uGYrv4{6vZ z>xNw^*B~J&13LN7lUhG}xG?W3Z4{S*-Ny%T#XBdAxb+Mj?p;Q^GqZGu+%~x4!V1M* z$vEbJ06g2Z@mj?`lKATzwDVkwO=}tYpmi7?N~fUrieVxklZ8s5jpS|pJSZD1qwbeK z!S}9vWY63xe37;t%tzy)@oE5QX0f1F01w@;Y5)_f-oSCEDD-&P46=LPV%?HE#JwdD z{Ed=O+)fJZFFBB&pjbTP--xsOrg7m5Gl-4|MXsX5A`vh2$yl=-+5oNd;F_!A$nR$};z z?pb2>kQ^Eh#M0ls*bnQaKjE%3R*?D5k+z>mflH-dXqnhCRPf4!E575v?tOtMT1RpJ7LG96WKX!SR@%DCpygdkr#ZvQ-6c$g85?7pvhOJ6`(KWefg% zCW3xn48c3Cnl_0%0P8urP`2wj9?o*1EfJ?+)t8f0+2<(uB&;DmZE<)ncN`Tt9^rk? zU{vM(4imc%5J8r!$n|0wiagzjwukqT*0{@H%hgO{8110k6}PCyyWusR z0*oI+@iH^u)La2&l6Pp&9YEVOF~}(Yiffvy@s|y{;3=UF6F+)j?yc(($XkP=M?Qo1 zl|`syvmEY}ZiTY*O~ids1akUTL3mjTZuShvh&N9`VAuy2i+Mn9t~%9Ru@PtPm!M;E zAKv-VN8T~o-e#*;&?3DOIPlyI?vMV&wSryn$Y>P~$=)QY-Gk7ycL>GwKj1a(dJ-|n zj#|(6z{ZhSyqMBWM{|pCru;RPJ@pd11f$9LqfIbR!IjP(s)x0od+__}MQ}>^6kgVo zf+Zu{DJ!FVZIc`$NA4ye<*&qV3s=xsp=1~Jqk= z^HK6R4>cnEh|}$DaO>^~a4PhJCH5T{HS3ANk+zh5!VqoLl}HauAGm}Uf`yJfteu}s z8gBNWgJleyl`F;@5^-eZ#oG|0y9v9LTo`t`J*Ycn2DjcVCmgnSQD}EMJ=toFcS<6O zQg0@{+C4)?eM3N>(*^W*4dD4Te6UTo4>z~Yf>lR0Ouecn`wkLN$PEJ7^io{CM;+r; z=74A260&;ZFL0#68pBU8Z0rjP;Z;mEu=aMqG2{18xV4BLPPhXlhZV{C3}N^&Q%qD= z4nY6ar64}+4Vo8D5l8l6=(^`gjU+5!@kBHB9!!F3t7X78L>Ja8+K{&#W#H9&8CM4C z!iPRYQ|aiwcy116j-J1;kt)QP)2+X zgvVLnjv!7_Z5|6{`C2G!eI7n+T}j@kQvKbMZ|~x*|=#di{#M623&F{XOitTuf`? z0ju41p?z!x78)L*p7#wwy=wu?=A}ZJ)jKkx+y|{gTqKI&_s$BiMdKPLP(A(x#uDuy zbF~Rg>r+9U4kJ8J6Nd_S4${WuT$tDLnql)aMzo0|( zhiGquF3Ne=(;3eI7<|Jx$?^Zk=kcazP9|QZ-d+<4vhu$C6gW(_%>Kg2Z*-xse z>QFm8j8I3n8wa4GRG#dcvkZS6GXr0aU~E?}rdb~sfSs8Q7kOALaNF_rmt7P=5SGH@XNv<3(Be4<)_$Wx&a#{ z%z#HogtSlP!AZ zzb7;E?n3wvN4mKr49tu5AV2H@xNApIulfD(>f;(B=C+X$06GmK`R6d^TU?34_OXz^ zPzN?&JAi%tL&#~y=m)e98C-pbX--qp*>fLS<;_tsBp=FMTEKr~DJqxUpvxXy0&9o4 za6GLF4mP(B-#4Yfq zBjd|3sdJRLWG}}bTZG8Gd_7!ES3vLkBapQ$fQpnmlCa!LiS1cvl;4);i!G?vJEC=nPt_^PpGG zZrsMU0Ox)4!;NcrL9gdK9=!CJo@pt)JZyje0%)W@)8`x1sDixZg zwnFshjgYy$3{L6Jr|J8rurxmn5=4Zc*~fr3L@J@(UUfVsWs0w)JLs<6j<{fW0X+dP z@pPy+Y2EM^J{n!8HKYlT3p0ESo!h{OVFP&GavE-HA0;0>>!9;i5Bk29!2C;&)U@F{ zsu@NgYt%awf8|F%`Lsb!&~`fWiUpP(O{Ke?I`NCv9olBR40kEcgKw$kaP_e>!wMPu8zsF?hvw(@$9#(Mftads25U&Nn6Xv zhM-nx4*pJ0G%I4lnx(|Sq#XtL>~Jp$I2`b*fVViwFVkMZi^uPj-l)R3xN-V_mx$M%rY_>BCACyD|;p(qEZBS(qYtm{i`!HKBP8fj~ z1NE@s;ym`P=pmAxsbTbaFWG08DobyShV7&yxHQmNbiMJ8xw!#s{H%o#ll{1DTtMkN ziG9x2uvhV2tX;a1JIfmJvGOgoUOtu=QXcd2;8^+2VFUI!#Iv*{39;?;#FH=i{L{Rr zoOB`#71s@=)h}C)elb%dC#Uj+zBx7zE5Mk9$HbFdyvrOUrbf?!;`xK@G$V_>Oyh*A zZUlN>zmEM^eNge`K0m{S!^a(m*@6mg{u?U)RPJET+5y69=49q}HI=LW*0D?5NBm}f z4K_J>qBLn6jJoE*xO^wX{L65;J`nX2&Iy-~5y(y1A~a51X3DU6w0V`lU*WTmC)c8- zp)L+Mj^miXu9&pS78QF}i?ykv_|)f>sC&E^8a72D?cgeIT2{mjzu)j|eoL5zp2F0m zL9AXoo8M*}ktYKh5mHfxUA=X9F2)1v4W7g2V>3CnUp-cT_|9{yayj?NB%!a-0l%lc zlwYrz^GIVmlwWAhHv_8R{$VritOKOo$r!vg9<1o}Z=P&1M3RfNSSgivYi+IF?l}(v~OUON0RqwD6)?{6bNryqKMyw-8U` zBnGw2lb#*FviofHq5=4He4vFGt~<}LL2?1@i!PSgJC@OBDh=!6Mkf5|T# z@p{6w+rnAa_qp(Yll^br&CvE>J}n1a#YPKX+9~WrcycDU?pNY}H&fYWMGit*4#w+w znWDVo1x`r|heA#|x4XU*4kybYowPafcs9b!U&D0bL1wr%!s8!@y?l2fezHB+pVtu; z8E5gx)=f+}x`xYJ1WP@KzF0VJo&2eOid&1`h~>XuBIn$6X)>ZCKD78M%ATFYJ(pKP zud*8IBaR8R3#$;h?y9i+F90ukSBaT59q_D9O=wS!$Ac@jQtxR1U*jVE++%Sf*pF+k zXfUV#->w9C!0*c`(Y)55Swphqii;L3ZT_$4arZ@#|9SCwojN9(Ka&HNcww{MKwh|U zn?rmD!fkGAR_Z;MRa;!pa`Hm)^{E%Ww;Lus4l83r&-tAGO^tzN9i-1vBl?AU%J`%D z=r+Zf@AQ;GudWQs2;-UA>B29qGX^YOCXV#&fEf|%#QcY!dGkb!jPttTXeSL{ZLh@q1gxFS1xm6UT56ibsHrHKar4V zCobaz$3EyNqO968dt{?*TDX?_N(-cc?n^k<<%l0)>yh~NmdNgXmt~gPVt{F9{BVo9+gc{Z?Un5V%eMQ8ps|c;kV~k_n{wBg^=S>849gcVA!)5uEGWJiqgTqa}9JgbQ+%8TaK`&0;m515XatAV{59iGp zjSJmIQtoVlm}mXr_a{hd8Cf#YZw?;BRncznMefu&3AxTy44+;W}t^Cna0)H~L!LhXuwKb;jsb;az>An#0 zW3#0~Ni~~Uy^t4=uf)iWw{T_CDwh3xO&|9x*^tXo>E;-brYhH_^+n?K3U09LjgD_xW9TOdx>~`#{R^H|(~&o`db6ra5EHZ9 zx$Lu%+)?O?g*R7=)&)Iqsi-|ag;XHm>wh?;c$aN0F3I4uJa%$Pqh4Vtrk%Qv*G_KN4)W$mAH8741XA_iVHDMsn8)$IGVU~|Bi*S zuYoG+Ll*I`p)xcQ#!Ef*1x)Rs$=HC)7@HPb-W8kgbf>b#eOdF~ zl6F0nXq8pN{Hz_cYd;^abdJIx>oHK5g5?=Mam-~CwEh3}Aju&pHW!?4RsppoS}ffX zEnZ~C^VrcLFiwm{Ma?p?rK=(g6uZz!t%^nJ71BH5Fxpit$6-Y+#5(L3A9oBuN&9-r zjw)zr_D!r(SP#>k*Ra@C9V-i-Vc6VMW^Vo@d%SdE^qbXkYV~dY?rp*l|AoxxwoxdY zI?9f&zoBN5$&*WBFtkHG+U{?X<3Fc!K*y6vZn=afk_@Hl`OD17nkTky-or5c4J^KI z#z)mH1hiLkM3tSK6mExS#WRJc%0$kKxz78aEupQa_0MN)#hzJuGXCc<*vI_A$^?J> z{pg3Wr>DbmYG*!rqJ+<@LTT5}hVr-ZWt*kW*5C9WTqhM9;~B7K2M?Y~g#OvPTu^d=x%S6! z;N~f|a`VT!tzGf8?Kn9>dmKNUllcBa8#Vd`JUQk!%pO-`i$*6X_br#rj<3h6&fEC$ z!4m9wa!y_>Jj8{L5u)FMeTa*8730=sqgE>c=Eggybk9oe`kToV*TM2m6L9Bu7^^Ct zGxYHT^sI5m~UCi2HNB52`0_>J}#&Xvn> zb#8a)HTt07`E)+=oym>KUy#^r50eA0h!H>h88QEoSUR$SE_cm1C*O}R^vXp**-e&Y zHPLc+d!~j&vs?dOY-K-P-mok|t)&fD>)qq`r$isoLv((v;r z3|rq#ww&)tj|)Fw?Q;)x`yV53!#o`BdJ-#c4}+RsBKMB>McULY^02Beo|Z+RPvkMo zT{#LVw-kAL;e0XNDie)5Zgf$2L8G8SV$9G~+;8uohc)2SI#&LuIgC*T2Vhy?hxU6m z@~OvH9{=%+&HQ$=eBVg%Pm=#(x1V~a(|BmoTrn@L6^0nuLhN><~krVHFh8l!cuuK0H1 zF3vnYianEu;^6!~$f;|F!eP6`;-o7m4_hgg+$h7|**9d(OJ6$bwv_RA^zgUiB5`Qy zW{e8zFUB~lGCkH+{`bWZv!6NA%gmZ{0)B|Mo@d!U$4@*otH!6#i`loT6JysO5a&I# zaYFaBtX{Mdt4G}uYRxC0{XPT4>|Diun}*1E`)uqf?1m{(BeBPIq6}Rb!LRp@qFZ4E zchC7C-=pHcRD>76>lbC&FHhX4Hb#;z_zAJ12W_xm6j8 z$88d!zngRMfnxUiY0mu8R2gO&hRHf#xp&NHw6v(<<%~;k*YANbA8x|SX{6A97fF@U zx3c)%OezoZ68pC&<5yuWLQO9-*r69f^Dp7A)?@_E^FT!I6*Sx4NGsK?P_{mZc!M8e zYuG0i)MSgT*E29|WCJ=^R=~TXBiqT|{E_0zH3u}1=v^lR+V*4Y$!I)$una%d`iZ51 zCg?xO1n&9wS%+xEepg4%ruW#s?g#^hrwOwy?HM`JL=4x@LE_V1T)j7rXII~)%gHP( zoKnY!8yE7oJRno@>}a`AAFWoJQ%zFdAKQ%Z3Y*7v9vaL~xiRo}Jt* z>-6@ZQmau8yxarn9_1|RbBYB`AH|;0J7_UhQQ8e#50$<8GK*dDvtzaxKf)Ou9@ul3 zmN`a5jS*w#Ok=LmWLZ7l8{OZP;O!n;s=v#lV)0JoXnzsQ_s@r!uBF)BvpXs^Tgyjv zhY=G!1_ndkala`DdLn95Fn1ccu-!i{thI{6(bs#}Qo)z{aq2WXK9oM&k4ig*Yfv~n z0akBcAk^lTXdgcgAFK@cAkmz|GtET!^1<|oC`HZB-B_A^f%_)EW&WHFV!*?JjJo-T zFTK9=)vF9rG7J{ES)8?KMXM358u6?gSv~rT_ z50y~%xdn{WpI~q6VmWz49Hx}c7w*@uLS`)!iH%9LJ9b&xHe18um(~ z-zvV|4uOqkI>*mDLv4-ja>v#Qtd7*+@Ov@1)76c7?H@q(T`%$9`a^K*l7{=o_v5Yq zOq?%2&+BC`=%jUt23_`2?b<@>4U3iGgMZ@8ni9;;Yk?jUSIGRXKD_v6w0t5KF=(yi z>*$_%`{$W3ZQU0SJA8-F(_vVBq5!U@kKr=&rR>)wgAGo`Ox@Rs8NKv5cVQ6Zz2hb~=gi6Ms*<(e#F?=nP-hHQ?@k3FU z+Kjyy#fb7DdwH$A7$!qUab26ENLdt)p5=~ku>KD@3j-Nvu^NptPl#TX4>@yC0X)eaUGQ-XF)5WIxM;wUv@1ek+pftv2uMLBEMLm zi{b@FiE88?9)*oRpHT0OKSo|_Ei{HG!g5>-8Xn7__ogA77SN7Q7AMKzZj({;?yuaq z<{|?}4wJ7_R2fAx5fNO6zkb#*nqG!sw@cVNS)Wl)JXxSo!j8XEMKh&kJbLRFkL53; zv&^Q&=;pYPv`j1sYT`JhC^Xv>%T3Kcq3(r1CyidzJ!t{ckOt9Yejd4f6*znC0p32T zB0d_M(`#s;+}S(^^0%p1(ngalZ2H z^>Qrx`-wpsF8JMRrqDwtc-cgXuJilw)w6L}XS)q%wh3&#Ee$GHl;z(&4Sc3HOwOnR ze=VLwr+531u1L`;rT`CinwecLfsYznB-K*@0r2qWpIQaH>pbXWslIQA(VcfTEN@yy_h-95np}# zvc=lbn7C#eTdnVkz|L0k*2z!Yamfrtk5gE7xKJwWNQYZWrs%2Mo9CC$hW^|zdiNgA zE=PBH95DbxqpfH zdd!romRe)&`)2s?xdaim9-QVH!|{unu}ffIE`Pp<$>l5LsfN?A{kciTz3a*1W+o!> z;aqrqRACQK4|uc*78i$>(m6Ln#x~o4nX?KpI3k6rcQ(s8N7G=_;ksxWoDKWxaJKm} z8S{fYnB?~yW;^cSWT_8&`+7?ITm!89^n@c74^ub(4Yz(ffSjlLa>$Pri1{@a;gbq@ z(Jcj&EHY3(tq($?9wGbAN%6y|8trWx(J9@6p)+e3IXfCKN?@WObh3CIUNz=6r*xbcZo>usXRb#tzVuc^;ijCxu;(1sf@{>EJKGnqa@TvRd!OaKHTv*cYD#%ZLA*J9iO+YN$dZeD_-Mg!_Uzll@y`v#lY*tN zJY$DI9V5J3_epB>{Lc4xZ_6r`augNC$b_SB@M=i3xclf7*KCXy%1bioZZ-qy$HVdX z(_}d?<_fPIF_3Q((-?i=EWQlQLaTipgni6dc6f6dud_Q~XRkqAI?;`0UlvFm%d?n# zeH1en9L1+L-SEvV2Bq=^Dk>??)3z3ZoQD3PpPo9l@qS(rD3DuE>Y2aFP}}=i9sG)nCfVN5Svw)tY1#0 zBkoL@q=s1Q2N<#UGpf`bus-q;9FJ^6ztyj$+lD00xJX%NlFB#zlB9989<3C}^>426 zs@g}{VZlO9?wKRIs)Vq9v*hYLCn`Qv7R5u4VD+B)lYV7ZY>Io^_xOOC}uBQm=AE$X;?fa#Mr+tF|nqDGxBjDz~N$hO-hk-sP#me#f zF-Pk?tKNTP{&OE0?X{E{n?GalnolrqZOom!wUB;c6m2~%c z!ZZHmeD0Bh${G#)HEcz<<-^z|KZ2>dQ`oJUf(Y?l$UiE_#U!)tIJ8;?7q6SqIL(x6 zCl6;%M<0f~v*z0_;oRFbjlZKF;OpQ5S{$wu%O*X>idpBd>`)TJcYhN%ZtceU+1?_& z`F=!(8u8AiAE@3iRd$-A!mZw)sbhEp1D_mYabjHsa2G<%cz^d9`jFFIy5O4=-_Oze{{pb4*O0ZjUG(RW5&GiNw1f8PRV5 zJ|s^^m+ITtTV^k2+|+}cm$mp%>I?7DW7sSw5mK|A47~CXhxwfvI1TmC*JAOjb~bf$e6aijJ(qeCztF-D~(Vs_Y2+U@y7%^RjHeSC@2UOba6-BWpFc$Uz|CpaISA_6`{FztN@xukS4H+DWF zTmGJfU(?UhXkkm@qC2LX6&Tz4p*XkeEiy*$;`26+$nIT$#JKP5`stDgeU*Wq2@WE5 z-%k$p3=u1S8Nh5}PpOuA2U}ack|S4JBE2$-f2L`|{pxt^w>M&mU9223$_NilH*)CL z-<;N>kMN18;;KIHu{m=T6;9X6@n@3Q>*WP@yY~lw*VZG~+XOB*m(Xxy6|^_k^PX{E z+;aED^d)LMqh2oikNFGD!N1ugs&S%lu^9aL8|wR7%Wrec5}xFWzRj3YeeiU5sj9vM7dd`<3;;bALy zY~VQFsrHxijqW4FVW@nmp~6WDlf(*58|rjFi}YdbaO!mtEn5n{IkQGq7T99xy+%1- zQ-hBq)WwH;O>A~8PA)Z3K)dY&kiB&Jzbxhp1J9Yl^H&JxjVQ&2Cr0vaz6X?lP7`CA zd@$ZQO!)iGhQ-1WbSpnfwIv7fEU*P8)_RJNdV6jd*cm&fG(&_@XHFgMf;-E@F`#We zw`jK!zm)><$onuFzL#)7pLxRd*?)*`oG&KlY@?-O7vb2yIrAqE7Sq@5!DrJ?=rhco z`Mo!YUUx3hpf*n0x*UM>p~3jl_7V+UV=zPJ@tkrrMtupU?$``j>0N~S1#xnkUTZ|< zn`7&9FKEAU7eTIHvB5C~VGHlVI@=W)Aty0tNi2S)cIMUBFQv}tcBntFA7vjNGAU1k zZs$umXRWpv_(PeUtsJ12sDwHXPpDOlLSaoXn{PB`ph~sOQ)yyj#~*ZZt44bBR5pAw zpjP!Bo_0M=%d35v@%sRWXP!lY>pe8+eiY8>3s`7)hX!tIDBU74WKnxsD<7iuhkRId zw-U!^e8BM@&xC5&8n_)wm3tn~f%b7FY}|DZZ_}d0+B>#1F{?z2xRs2^j=_?CR~WoY zOB6d@hlrcY&Vh-zmE9!mXYJyjU-c}t-N8)1JA8TM3_80XlL5jV^N;=W8BYf=SS*$6 zH_hPFZEM7e_QR0XVY!%SV9(Xt|K*p7m9W`*NUS=UhU6JvMehD2o*L?m^xz+9jdnZY_o-^iEryd-?w+Y@Ow~MIobG*>@C;!Yn zhB?{FGAY-JTK$KJRgdDJdaWOJTsVY>&zj@p`zM%Uu#yggGdU~$EzkFAg2jpX+@y5@ zb7nphbLQ^n`(=e9dBI)&u=^>J++BD&<2rU+@`SatrC-fd_W5y;`=VDc)v=>2%6CQZ zTTdD()#G$PD7CzTL1u-n^@TRa&aNcha2> z3!TKfkt?|DZm=vdbHZmeQ(@@e1IrZ_$@rIFP*$-U&SpLs5?_V>H^yW7sef6sgCmV! z#*6sMKh#*)m5b-dB&4)p!H15R!SCs?#@8hwR7krZlTTgQNmg|kbg_A zi}q8_Vcx0va-`EB4pzM?yFX};PGwKzukp9xG&vm+ceNN+znR(w(|K>6uN*Y)H%x-- zWst5Z7xpwl-?^$xHRvd>O|n9ps8r$T=YeDE*1;oUDs#sK$ieN}G2&)3X*p#ehMdTd zgIrr8=tYR=e%=`qdRmLG`bU_${kMFWb%UoD?~z72)p#QEW&BwU?5`gzH1%EBzU~%3 z9N)t8$$4^;$rR|kHAX@7NM3fdMf-Jaq2781cW!Io;JOu-4d>>uh}2+$c{iokO*(mSWo|P5d3NF2{X6!;>m6-xBkY0c3(xLizY8FeT9psI^z0T zMWHgri>bRWGS|1&pOtYPm?8+p0L2_LKva!S!JE>Ex* zJ|Q8f+SOKk$k#x@#_nQy>(6jqa8Mj-R7TCQB)Qbp1Gn}ckvhg!+$UpZXPdpk9<0*~8IG`Ps#;%r&mKn12(l4=( zJ5e5}f=c6V@DR0pmJmiKCqO ze)A)7b%81}?4;Z{;vQ7>C&AOGB@UPe;p6*8I^Qf2XD7Tybh;)FF5knWZMwmGup_?M zmP%vS6P&cEUL0v0L7)CAqIULoSWoOC>^@HAEc0=^_2JXMKE;}6BfHUc(`)%syA5|- z*#*18Oe`I`2>CLZB^_VLvlG_v!$%8hzj=mJA3|mC>m6|-wT)1+v19SM1vvGzjCXe% z!q@%{1Fn9O`_^x#TjE!#SKOJVofG-dzUb>9dq6C^bmh@V{yBvISsEJqF3YzY3)0lvph#p*?0id26)pt{s*4NPC{WqOTK=3 zOHQ$kVRqjY)cvQSJ4%!AePvHfm{5w{bKB9^L`UwMX^gp{Mi_2?6o=ZSNc)Xf;MUEZ z-%r=F%@u!KSaqKcuWX_FcQ9hYn`57QHI@if`Q^w{#;@&6{p$1BFrWfizm5Ja<2t!} z%K$p88IKp?-5Bt=5CgBBLf$}qu3B}C*C!OQa-Za&kwFrlc+QM|vGq$n3OrP>C+;Bfocw98+l)V@6E@Txv<~Xw;Ko^dR zX?(EEj~$n3!#?{o@7D%nbU`3@H8i1Ff->6uOviy%5}LW)xZuHCEb=jAmn-Tx`0`8bv??UC8mtt94-So*yFa$m2*O);h`HS^OI)r^tRKFDSDI3zZ~Z@AbLGix79u}c2|8W&O6N@EmkgTz^L6LMb)BbP&RdB z+}xQ^**Qd-Bxf^YbUJ2?eT1as0+~Eb3wwJ!m504=L202S;_ok`?z6|@%a7qu*LY9G z|0dzRx1Ee~>r9hhuA+R{SjH?qE#Cdl-kC@B{H1aHecM;c(qhX}WN9yJN~sW%gtTd; zNTp3#B1;=76|z^dWC=yKibA4jFS}?*vJ@%qGiH8f`OVCkIcLt9`D>nYzUO}4ulqdr zd!Ogt@A-VsxqsZ6CQ=TL#RRdj)WbU23YTLrU%7(o35_S)%sosncpY^JFJXS&Q;F}h zVsm@TV$yqCw)ABa-sx)a<%ww&QmV}Q$Xun_{mgM)(jDrWVI_^%2D#&ViB))i^$8cGF>TB-DPoA=%L+$-& z_vn+D95M*=vcjo3B!V)^UFh@LJe)rM0965+80=+CsV}lwuQmNqJ?b0rmko6JSRuCM zX<~iZDq3@HA&HlVFwN7sbZbU9i+rj>*>*8p>&Q%u22!bJ{POr zgH(ytRNyfa&$a|m<~(~8cUNbyls?OIiHGW9_9HbkD*uET|R_LU^LT?9XDS_MPon(tLw>Fz6_0z+(@B) z03=!sXq`kR8=#y)Yo6X^YDe=Rb8-xhPb#EA0|p@USTlOO+-PcJ2u%)(#+*`FNDuer zOJq($rOcB?+^Z$k74BT5-4CkEU-K^;y~*&zWNiJg6T*jWC~VeYa$FLRrt$F*Q#*@! z=?wnYzQTIi7EG`EL8ZCVuz%2ergmjKEv~8~IL)H4VQ-nPu_g6n93Y`A6}(Av;11`0 zpwM(N)vZv6>);9)8)p32iI#*m4;6J^(kQDzY^ep@ zaz`4(k14YT?|OWcwPlLBRSMH3Vzf)ORcxHqHtN`;M~+D?G{s>Q*(5w8i}})QsK$3n?(0VmD@Rd~OeMRzrkv`ZZsaze z?)8*s%6ICzTcs~ur!vsm-Frea;LpQa|u}TQ=IU&LAoXaP1+`mxfdMV1}%lHH#BW$R-h|5k1Pz#jjTW@?r z?D=9Id3ij=zqx>T_eC^rT`U_`o`jpWqxpi~8>sq>6>8JtAR|2-L(ARBy3aRuNA?{( zzSab-$_<2&Bpgt&ML@Y&$u8tm zFqiGO>%b1xICfT|2gT*u+-tK18ZO!*L$n)88TuG~dI$nsttcpeJ6%6p$e;L3#MO0= z@a?cJbT2y4J#jmlsCJxhJy1-OTfCuLxrBZom5DFDj9roAnB&?`EX+C066^~BF%Jw` znt|s{y6o%Mw-lA3M{cU&0{)L8qRxK20{H`51pQPh1zxAU}y9eQskeR#JvI- zI?qN$dn#@gDY3ws&rq20f{#~ip*fd*cwDc=R5LG<9^J0O)`2_t7U3UQ@70$E)y~G8 z7ZZ4EwjoST-{87FFG#|3E?J&>i&zC4Qfm%DVptuU`o$VQ)SpuOoMF&P?8BQ>OffxN zj_*9+2&F@nyn4(K5^DI$zn_<;QBdL^JBUuHN$?*pzTt)6R*;4WT|An_tR45#l5#8F zsGCmJ@4#v%Hc-Txz2ti@9}AN8xX4~(^huRPtFs-p2wSjA!Fm+9)R5W&ui{2%B*m?1 z#pOxPOyk~lI&o|bQ*#SNe-{zHYtK>&9-oAA7Z1ex4B=N2zv1m8b#&cNq)AKV@aff2 zw0>=&8K?Ww@(wMsUhY69Asx)BP8y@fPQH<+d%XQwVA2hO{v) z2Uc%pv%16KC^zwDkB>iw*{kF1dVVa)h}w|EgB=LGd63CY9EpMJz1Zp63AFS_6%It4 zq%WEK_}v`ls4o?EA2*qpm8_xxrO_fX`s3ztzV^M%*5e&p9=h8+dlXwu;{9xq}^ z>9?KP!poascK8LG()Na&6bDetIcJg#>Ebpc3h?yecWy3Lk6ZP#*cI;-(rQg(oAfkb z)hmSZ^Cm+xBapVr4~42kIFr*+qz{tk$$L^f0%P0RA@?8}Z#@SOuJj=dp_ydiyO8p= zjhTatE{S=DLu%DbntZSaaU)7FE;*2EuPgvFIYvI-sW`kqmCvbpgUOE`&}pXxQmyx6 z=j%Vh?Av7)X}z8F*M8-(;(>G_BZ|-Z8jE*7-{A&|UrBA+L`vxp!SG2Fndkil*pyHP zk>wI(9&JRt@{e&imexSGS1+&P}~F59#I zMFkW;Y&9!qgtsfk(h1!b9BOu$s7_Dh;GPL?hFXoCBfzmZW@ z6^Req&t^=q#JPeg6f;vCZpj^JDw~KYinF<8K>_**7V+dG{@5D(mH9YKqRDNNEc`_T ztv%|+){V`hp4^ArGJ7VKeW_!z`r=3_9f_D#c6ijgk|Hg<;d0c2`dfz3+04sqW2_K7 z^sRV}j5ImDAI1(RHqpi~1Ja=iGKhJ{4^5~ezfm2ynbS=TbM)Y1J)h1NPvr^P6R70v z4d~wKfX&!SKJdmGTYGboLu=S`Nmv6p~oAcUnXjvNFwCcwcE-j}I;%~s#rO~!l(EU%Jpnt6sA7$=R zUBF>}V}l*lEh0kCDIe$_Wcbm)hg6O!ajDIfSkXt1k8$0PUXQ2pN0RnbbjOz` zjJylw@4Km-hg^h4ObI;K#T9}&tF{(=^j zBiU|34t21VMKZ{@ZA6HO4Gs=<;2S6@c-3m#xdae?_ zo|dP!3nio*wTlX}{ZRL2Hza(PvwLAec)!yEx+1FNU44w}m;Qi3ttp(GL0W3}5gZ~% zZ?|i*Lbc(Ptv!%!sjwsU@tbgNohKE>Sn%l`?bJDbIky=3i3IGw@t%yuwB0Zc3SI+g z__981xLgv98-uuZtSjQuce9`&NyronVPZ%6z}CHq!UnH_iLxYXxjX^#^T}}g z3-r$V407vDR(cVLnzWm_emF&PO$}V@q7_ZG8Vm2v$GE#;D%5}IBIeFhR36F4gb+`D zxnCI4*PNo_%qD`TO`UlO~PsF*#0cZ z+L7|~yLo$13)Mubu+?)`l7ojEi+dsWfpn zC7%TBHk~GsL4CQT&sU7PzK5b)b|cWhgbW|$(Azgd`QS;(q$u@~rR(3o&@D04c4Qqn z-f`psT#)RuoOy_|J)QFHh5oy{&{Z!8OQ%(sebbyt*}kTf6(+3AZzK7QA#OgvoW5r5 z;UPQpkziItHL59;l5>w@j3Vfh|92Q@+{eY;#5Yf9!!g-wB#~Z#gR7p9?~ZlkvFRnh zu+xh|RG!kNxqZmTOP<-?oQ;f5ITCtjKx3!vWA$e_+SYDm8<$+8omQLpck2w;W?f*P zYZlXT{ZuO3+>0bPZ^y&1r{wtf5VbcoQGovup0;u+be;&XM;i)h$Nf!Qa;XVT5O?4i z`$VYZj1x?gy-__jHw%Eh%}@G0RK^T^&oC$>tlbtW6}YVj!6<0Xc| z{8$zeQA%gz%%E)&KV|59u!-N<#C))xNPmn z?TaQ-bhba+=@gG`kqvO}vj-D;jIm>x5biJEiy?ixNaso^?iVh>ggdWz`qFP?Y-BiM#ne>e$FI|l7jZL^QoKh*sp}24Yi7+&){}^8i)3A#$`Mer&dNX;CS}(|ZpM;6YJn}YM$}{ZZXxPK06g66u z`d;71N02Xx@4Cvh52--XSL^4wRUWM34yWRD7N2VbS( zE+Vw=mH|08&7fsd=U_n9J4$nwLE)5m9F@O~i3(G3$t52>3612Et3c}GAJQAEFSxvX zBwJ-r0*McGh?fhbo%@4fS~UV?u0bq>1Zk#70Rm<3(1zaf*gtO{Y8>y-)d>k?z%BSj zt9|fZW=LLEDdc&*idjaFf<8IWOsQ+A=uu*MC*r7KTwlIvdJAg4t>lrr7SUGq^T@qk zPi1mD@VGJn+VijR?cGWkGOdtB9B@POLwSBZwUT6V48hB^u+aJjKHmI9`$BiIH>s)A z)b2aoeIZ9#ovl>)@eO>sZ_+~RNVredrY&a=@-=EY z6x1riKiSs6@yJsqDENk4=Gb$~@l6nJXy$qfFKP9}Al7dyqtg}dF!AGIy5`@P#2Pc8 zIS$Ov?>LFfdQA_ObRepJHtRY&5$3^P_!>b;njc(9k!xKj{^N7Ds=$I?el%k>Md{?6 zr$HLaGsx9`CJ$=8NckgL`GCfu^x}IVO2*EhyVhqAzAO(u@11#*Y7^=oOyfmTuW(%P z1y-BtQ0x%}oVa3+!F2)ra9Jzz145}vavRA_-oZ+gb*N>?SiCj6MAIh5^YlK}^qNUi zk@k7gt?uL}%bjs!#smzvIEa?G$?U3mF0Sp|&8L}eq?F~V%+{KjXQ0M`)edACrF#of=HTSH2`My0vP%>gk2iFA2Y%m`F&Ex z=pbAQEa*DhEs!6Nj7yQP3kYn+=?#IMx*2GSa=CMPMicwn}_&_Da=fJ6D?aK z&Fe)Xkh(LAlHFclVBJ%8*x?qviHU-Y!UlT(P=lOhT`0g?ik$rC!mhrBy7)Y@ZxrD+ zg+JeMv%}Cm_aVh}tYgup&oFea2-|W(j@nF4@VmKtaP)LE>Ewve(!o(Y@pTq1tt_K( zB`ezNu0~<^U!iVh0yLxd(yeI^dE1l2Sn<>EM{X-E?=4FO&V)?0bYA%C07hvBQp5^> zIFG!9JsL)|U~?n?GBOPI?fbc%>qeyb45RmtKhc(}x2XEYVH&;X3AUzh!4m85?6lb? zI@(ptnf66mKW8E9@v(%faXamA%ckd{+qij&D;XuMA=il~XkOQD3OLX}ZDV_J(;A~>*2dC$K%X?T&ofQ=8&n*U#MR8J$-uS`?>yQ>S62kkf)Pg`HB5jkhZ{g< zaR!}rUx@q4^Lesq2~B%-9g`nAVo{t18W(lKa918v5gvtAJp&Mx@CKC=Y zN|*C?&@3rV+xvZ@Q?~8oYVb* z0nB6?nba-AOrq`)3sfYc^V7NDH^EgMATYYF}#!Of@UgVxxJ20)QH?>B~pmX{< z{v@P|43|D()!U*dHrt9c2T7vCFNT$$n?r{#?V)Rpf|Pd1hc)MJ$C~?j^kl^}GI?vr zod%qt>l%`*woebuw_XC1$(!J~TA0~~m63Dr1zdbk4%)@jp#LBVH;=l|l|K4-oV^{Z zrUaAF%^svzd?1xG_B^q&ld_C-@k81lS2G?mzntCFW_uQ6@7^REuhq~UF$czqiS%4Z zl=gn~qrCDKxM<(S-aXaS$6T4|sfwa+gb@umV~UKng>YRu8iEsLFe>>16|H!}ubNns z-L%q7v^mu2Z6WhtV(|+JjZylUQJ0572bjvkNs3F zD1t2wsg&h5h&8WUNDq6xWIvpmFfwU3bBX%-o_iojuamM!WLp#to9>|1sr%{T=QA`g z*Pmk5pHX%AD+(QKikz`g?30-|Y)gomPbENpVqZRS!y(eldP4KEf6&OP8*KF3^>Erd z2oZ^Sc<^l$*L8}ds&SDty?hIO-z-m0H}#{!upoH3OCnP^o*9U`(WQ5ee9(Y2%#rh@ z;AQi0|7IgAI$w*?(>mzk6$_kDGi1plKvSf4Qi*sRJ#}nkYX|xw*K-w3D>J8_jT4x_ z>q3m1Q;xk!bE!gJo!vWaO5-YUMY(;AMa4(h$PnERFyJcrywya zA5RN7Q+=pI&Gy}F`o2@>pZF1{Osy!SPczy33F3-D6JFh0Oz}>sbm`MGoW1^>y*4;S z6GI=fK{k}2E{%<_eY%5E z9*^Wz35H~BoybZB8JfbEu#FaLsqO$Ht4MQX9xS74idytSu!1%2$)km-x-{B4hGwm^ z<_@xZu%_=IHdL;b2FaJu&X2m(pt}Ks=ai!ML^nT|)`SVAo@~|iPD&Z~jE#2RL?>h% z;ZU=Zf@XqSPJKfm=Qdz_dJmjOCGhUsT68SSo4+)>PI5apu>D!l6m)(JlgQYIgZ9gC zQaXiVWrm{r&P6IdI*u(Ks*IF<{b=3y-cYQ!gucyA$jaSg`yb4uQHB~2TN{H-^4Yv( zR9_PE9Zd4dJE-DK0N2wtq>$4dl>F2Yi>-R`<}t!JwtXXCWHAz(^^JM)5H(W2y_S8` zOQp!z<-E4S56z;U5$_bd46pCz?BM`S zdNBSARTe5!$OvudKDtjMw}u0 zC&D;k7%6>;q4Jmj^6*uHP0AT8sBPjJK6{}yQkQL2D?#+8RlGGYoIdBBKKs3lKVJ1BY~1k^KeEdhjmw+p~_FI*^(s#XqvGP z4@eq=lu-j|yd}qqa(}jby)&LSxsXz`2r_R5^WKk(Y5n1O@ZI$l_T8H7=%sv8(b&o3 za*vUE{0E54-h|PIiumG?YOvMsAgtDnI4LVAc{Srz`x-hSnoHLkwvu=5a5#=DVX3-z zV3G5YPwE$gj(83B&`k#$RwnX+x8@@0hbraUUD9zO!}XLuuEf8<=n{1QMU4@u0GiHXQuO6Axac`o1}|e)LdM z8vc;WPFjExITae?E5m&1eU~O>rfYVvmgX3Qo2~1&3edJ z4Zwrbw$!Ehh{dQh(fVTW!zYJOO;>;TUKgd=+uF&z{xfwan4u;(6(_{ANbYbSJegb0 zoL9}Kj$v6eNp}(%ovEO2GsV>3o&z=X!Uko>OHv%Cu{FfS4k~< zX_8En_Fv{2%|GXHJPPw8qj7Ak4w|=5#iXTEc#w-C?KOPI9P_#<{i+`m?w(AuJ)K$Y z%W$lAJ<2v2_`-EX0*>C2z_16|sOgnKVI!MKFZ(52#vGxq(yGX*xWGjEgJ^0Zk5UVx zB?AI@=tw{GXn*1%;hU)B+X;T`Z7uF!_>65a2KcZ!k9nUXpkF*wsR$v_QJb-|+nQpE zN+G_~gCsjL5Z)4s6Koxq$=^*at?jJZ%$L3gB=b)%p3#Ga^$@)}89`qSS-{*2WYAf} z4g09jO1&1Y{k#&XPer+a<5*-HWbpMpX`J78c!f@)d#chjs&OEVYL{nwLv(20o-Rnd z$)KPwLcFMRBurC2F`3LgSUqtwPAhq0fQ=Vvjah-7bYqx0>_)#y9BGO^u+6ch5}`X# zt=48$PFu+)`XX1Cl9u5Jn!2l#+;0l-mJ_RyK!eax?CrBd?sCKz<}B7F;I(AT5%YKk4LoH3a`Y7ArAf$#A2f+6p)&BBO+TFRZS zP4W?8@W@r6tCI>a!l0R+b$LOmITNv#c5I7-JH?F>VAP!nVcBDORGa)Fr+MQv9WhvL38J5e*1tvy}a9p?TS2z?}6!j*X#FamtToh zmvX4dSBuX&)ke*i>&fz2KNPIo$TmK3hq~?^R&iRHYy@p-;@%iIT_+l2Q3P&g#yU2f zM2Sf>TVHF2WyVEZR<{9x&tiFT*E&q>lR?+^rjbrd8B1;$OWy`7GLt+*{Fvr|d*W z&cD&WB-AxDwX}6~^~O(_ILXL(x{0aTjG42{XU~~yG0$?o)dK5|rNJ>ff>MbVzOA7pw5@5f1{Ct%B zW2}H6n24y5u!N+Tc(2}4(t=HfnfEQxCkad|pb zVd1I*jgLcRwT%5QsXqUA^A`f}x3^`B{Axx2E_b0{J_5gDMSk=7hkXBC{(rCkKL3AL zkH6Od(3%nE_~+af0hpN}jG5bn@wa_a0Qvz){@IuOcYV?Tz6$^sfA(GcyS`rdy=gN1 zS4?c0$fkcb^rm>BKk>Lfw*Se6^Zz4@{58L%Uv2WQwrr2^pIU`|zqOV}e#`U2@A9#P z)dG_RnUM{>43E#6kx^hj(4km%D+6FN+1|uG$lc4w*WJ&4hG&4im#2%rkDF)UDtqHV zPcJunD|at$2s*$)8#bfckVR zYh|11MgVaB_skXmuKbS8`jg+ypKRz~*>nJ?`@Nqn0JQv$&G}R8hu0O%26*}Zsh&UeM1kM5@^5<+V)&(Pe~TIVlieH#s0aTx|GGQEu=W7d-G9@%>LO6Z zU-p4E0NDRz{r<{y0KivWYA0KQ2Bu`+THmIV)ni^mWQ)}4jH%m8v9`qlL*leyW;SK3L+ z5@7S>Vb(PW1}%dz{?QPq7b#)%m7!2RISfik!!aOo1o{UnL&ie|l57ryECH4vhlDP9 zY;RG(mPd+MS2O@YR|aDB$w63@G#IlZhd?)238OrQLV``lA4oeB@TjUQj{nb_C9`Ci z?3pYiVJ`>_VL(J%Bb%UrQ;17zYck0UWFVQ0lL-c;6?fd)NUdTQi%XSK)Ran#+9e_? z)z(I&Ev?qZ8WmA%YH5pBrRTkOXL*@7OIpA0=Y98_bI&{X+~sWpIH%?ypFW42AydfM zVsJ?wV9O0gTuVR;fJQ*rH0s)f6dRGJR=`;*!F)(^$@&&>z1ECEDo3=XEZ+fu9A-G0 ztZ=w3a5Ur&)!U4)MRH*BnbCg@@W*R_-fx*u4wtc>jiyerZ?^@u)#i|TY=*7D9CA*xz(H$Z9myF=jBlcp(DzCs>>n6Ih8DF?Az4;! zM4r18c^{ZVFR-^+x0nIvDOOa` zM&ypzhAe~T0b?kx-(di##DWr^9VJaRl(?-ZS?vf>g$)%{kHV3Hp}ax+fHh=k$?=$7 z&KeW!G!<%Z5@H-@MuD#Y1)Rr%ZFad&YTqZBP(qC`4aUzoL_mFm84U+MhnmQlu=tju z?ml4I{Xq41l-z6T&ME_}G!>G_iHp?vR8H$*88Htjv3P{e0MuI~Slj{BJpi2fAP^Bg z6Y8SRHtw^P`)pDA?3`#t5xEod=!y2Rj{xU*d8|v-u@+iI2f6<_D4-%Wo`iNGhwqC~ZJAK!wo@6Ish~wYZ=EH2 zUK67MxegLh?3zxSbTS& zZUERg01OHL+PV>7J811hYshAq;x12$>A&n{IqC*6*s5yw#eVD5k|WNopCm|+B*b4(ad`G&j!d&nl_jTIv9<2J*z zVY^}c;ao$dFVA3cml!Yt%ozbzd{2!jp)TgQ10_ubC~@bbWDn2r8Z+`g(9Yiw0IIT~ z%2$r6rZQByOHuVf$%uRvQgSg|f*t<`OecT?>UlJEa$4c^O@x!GkvC!=vJT{g%%12v z91na9cs>TOBbwU@N&+klvYB98C|@VkeXL&geVpSO&V}u; z9VVX*o=JqYlL>?OnBbg}gEBe?IV0L@k4uW~6U$&ZupFT>r*ntBkRx?rg}z#7GS$ z`l>O}U4@BM0_~a>{Vlbi)MrI$6PNBBlr|I&DcA3a83U&f>Sho+RR5Yf6&g^upR*VO z>T4{h8RoW!Ey&}(n40WpoJsf+bHCiS!ib6kR+!wmitNu!zwkM#u4zYdyFE(8E@hrK zIWRbzFtveTxsUBlMwlWtV6@z3gzdNmreP~uS@t?JmE}sme0HTiZ4RMPmI0&d+BUEO z>%iQD1lK+Z({~y$e!CGhTTQ6wHN(-Kquj&P&$eLp5unUh z0((<2jP4?|xCyIIBOFxY(bVb2Lfm+e5D-2mv(NfOpHu{63sAoRus~10C>M*40Pf=s zj2kXQS)`2pm$Ls7)GZ^NvyxDKzv5q0Cx;}jF;~6a2z$f|qtAvdUn2A|n`QgAY6bzeTIh+II0gIx)o4Ho;X#rRd)`RtEvX9b3>r;%atC_I1IcaQ#Jb7&Qvusfd z!T9~y*edm#m}*%DB-P_>QjV=SpJr^6 zekW@DIw&eXMI-mf@=3CM84~Y(4-gR2+~Z7wAtbqCz9v~vPBYZ|!9mjid-N#hC!oH_ zh@!}JSlp)o-GqyoBM+!!mQWXd7YV;2htn;nr1O&edZeh|mF#yF8aEQ|VO$TYeiQ2I zePYA_n@_n;i2Tn%9=T%q4-v$@b2Xy57!t=gwhy9-dCCyJAvC#cklQnwAIBgI37g9QV5 zq1+a`2XIbdd!GdrO*yD=n^953_aj3NW&AC%XTn*UXF?AF^;0dFdi)gB4bMQy;hC@; zmf*XH2NStJ6S+SVX$B-CT&sHR#=^HE&!y&L7*BNYJ7R9Y05>7n~zsJN6Lpv)#uqJi}F0H>{q@V znA~Oz>?DjZ13ysW*3_MqX4v;=?;||`oYQlVPb-qv@hik-v`;fEaL|&ZXPWOM*yufH zx=8FB+tl+d1E6<5+bhef%*drejFwZm0p(X0j}#67^|dzC4jWN%*o49e_lNs!bQb`R z5z3j}yTm@-WKrs?n0>Mg7*#g{>;nSoa*^c5yCE z{ZtE19X4T_F9$a6kI8L8%kzW?vsgUeY3oL{-$`~BU|8hDmy@J-maF%z%Dw@hzR-xm zND+*_LiGKHaFB8DR?erXli2{Xj|l4KL0Atfc z#qLYY5fRI%y2h7y&lS7os?RZtu;%DuoO@&m79CuQ)AyZ?IXjnO`u63Ry!9N^_nwQI z_7!ltzYiyUOZPd(nD`ts!GJxf}IoD_axMAos8n%DX_Fp zMdJxV8}prqIOZ$NxZ*@D!bj_1JyNg8jUN*FWgU=M7teba;x zgQ_*xY6B~TI39gYie{H z9Y#1JlVNdB!j3!%e`2=E?W>HaIzA4T!&4O5gZUD62*0E1iS5KVor^U`SMWHk#G-?% zc%06|oSh!d<>xVZ>uS{Zu0c(E6P)h7aMCW_ak@5foTeL5Nf*QJvMF&pB%uDnB3yW6 zB32!ogeChX;zu}ErxDH*<6%8IL6IF} zE_x*TzU2$aGT#?*!2$_E=6+cQjIL|^ry7_3#S$)C5*rsy-C1Ww5mmuFq>gfIjAvRf zlYP~*pAz8*XG?gFsq0t$#OtZgJ#>zQ2hWY2TT|CNhij#Tk5GQ2gbD*qLL;-xsnYkZRFGh`f zHfm_9?iw5fK+RS(ZwIQk63TidSlbOSUJW?s=VIEZRk zmTVn|lJ+`Sh8MwcmxNz1NA{Rde}69SKT(ctM=P-Ih!c$mD=}wZ6|CE96q~ERCE?>e z(S38VQvd7sBvkxZT=Q9`u>&;zDc6WxcP?_bSwha4R@CjRKslWO%TP2*@h+Hv`m=Iz z)^;c6Z>_|v-YV3#SHp390W614N9czVK4h+y&-;!I@0=*ct4B-l+>ugDJ6HzmzH&u> z_HGIH|2P`&BBfrpN5ZdT@h;NZAs5*01h!TJy;VSaHE?`^Y^OaZkXRSbOeGULBKLPcXMpO=;21{fCMqZK-JS?GNubK;O-3YK9M%gLP zP4|v|nu01HpClK1gBzOf852z?re4jpcb@^`TURb@+thDe;<+NE`Y01V#PfZf2}N!v zidb&;B*-V_pgdBAa(5-lsSNhGPWZRM7G|GL2{}|1z3z+W*e>MJ`q*=9qd|SHsElkv zrMnlE6p8uklXb-eZ@2^$@&tF zemlf-tS=uGO?jwr=b|F4K9?$azgj2nE<0-7i&0App!Xj6pfXS7XU7GoCYP>FFNty8 zuQT5H2INx-Bo9Dk7L0!KR<2vaPSi&#Q12^8y}JzcY+vdDR9y}0s##aXx=Pknuugn4 zbWf)$8c(D5d054Jf&-tS#_0z9Y?c9sf2z*i#JaP=%0Ba?dQSdmA9arCcbqR{itkI9 z;=UMDs44lKuLSmE=lI@XU&l~Se^vMKf%v!}N6w)Y)sY#f_MO7HoQ`Umil~qIB*u-V zB+U!unV6;|<;{7D9piknFwQ*_<7jfyIqQ_~fjKB~*P(&wIR8t9J{f_zgENZDi*T+@@oD+;FqR&FJx15@bQ;*Nbtl`rzyEzR^9Vi3=lRR)Y4L2o2e2&0LVhHECk3(u(n3m ze4euA$-=(E>P}uLzt4|YQR>SK zJdeyMX^{636X)S^l+r$!J<9J6ZDxc~{5J zpLf`RYDT)rsFajrK+Zz-S_uFWv91he3IT*fgkCbjzW&%k65DRzQqSKv+2-!IxMeMb`-FzAk21l zg1r?`?U^Pk+gni4pxW!j>HLQQ6aEp8(<;Uxst^CmfXf*Ilv0hkfMd?*nDaPhu7{PF z2c0vmEI+`qr%*$`&|Lq9OaR#=*c!|(vP!USlRQcpmOOfKz4wU$pD^3gj9KTW23+%L zdYiqU8t_I2n;D-PaC+QEtgU>MaQ{lUegW@YX1s@N zgX(yz^Ll#xeQfMEDdHV*#15yA%O)$FZsmR7kSfn(c`nQCEa!Td<<&M+yGu~LNAI0- zKB}AYSkK3+<7->pe=kKXt<~Ls>tgpx7ogI8J}PN7qT{zkismJk^J3?`*iaH?pA)!r z7xA&yqjK#8KxXxQa-lL;Eu8xt?K+uc#4wX{v&f^<%zez|KB`a1N<6;f9M3;cNh7g% zLOJ?l`N=pVw$>TrV<{1&=r;tnBf545mFsbf%|psH#HM~1cJuM-!lA-Z>-~iWBi>-@ zqA^z6Q5`AgJeP5vOVx3pB9snA$I%KW_tn{y!+qiYG?XU!T;Mjs!<-iNnJXbTY|>o| zzh}EM=NfUIuq`Yyqlo)bv`2lykJ?4prh1+c>!WrhW|a8izfp?X%{twPb<7RI&Nrvsm0gk4vu()r8XR#4KWQ_a8 zeMr16u6b6@p#=r2?V*JGd-44sZ*DF3wTk;%&V4POlfQ?bv4+fp#)0T_j0X^Y3fYeX z1&8b*Zg;+>-J0Zf7XhGJJ8C19sP#Ef>#jg8l|Y$s9zdOI7R~(%DPt7Bh8HH!$B}5> zr(9@6@WO<7Xdzfy_18ho7mVm-UW$&9@*AC8RJrY_YA7Em9V#9y94Ls{f81)sj5Z_Q zi~26NaX-sZzDK*R)#r_=sHQsIJ>-OvV=Jnf`lKrN*Q6@CNz%NBDgm6c?Wk?KL#lP( zF4fZ4ByoQnvuP;-M&FkafY!A}3^B%A67JzvOD-kWrd*VB-^v^K`^-?mp!^#s%9oJe zU~^H0IsPrMp`?Wh5`J&EhsSn`{e0(|5-Lo3lO>*^AnrvMid>J{!wz;Eafqq8B|4vz zf728Do@O(^)-J(#ul~3_w%LdeH;ZwL{zhk;(dC?MMMZl)N@yIcL*flq>^+poMG@!1 zZh*brgq-~ezaN$Wsc8cICY_*&7#u;6+l&SK`?qLx;jJs?jWOD1%S zQmW@E0tm_fojiH+BmnGx)dT{tNm8*qW5T?tr9$p<3feu_PhA_7c9F=!oX8fto;xl54}iA`$0Yi z%le<=HU}kad79frWxtW&d7j&|yzZHJd(R88_Ay!AE}-vtJf_g~?CUzVyH*0Oku-LW zU8>zctJ)_=ms;)!5_W8e_p{|@ppRvPU4)UfgrR_{Yvj@upm={;2`#MeUr%swJ+zkX zTXpp7;7M{b5-rV&9`4yMD|i<9d|f*#q=n4MENy*`sA+_|dtnqCLI4WVwn-T_&Nf_jEkmZBNSawWp z+w!_v;uQ%H{fqkdyqYZA@s5}i?}_ugqn3DILO-+P{rLI%E?;$le zJwhj9tGhv+OP-tKW7BfITDoo&{ke+(IcHqD?h@_O$ic^ra-C_pi?sEN#pj$;IHfgnhP-;F(0&F@Z3|@)23L7Z{ZJ34ou(;|yI%Xt|QOo#t3!;dXV+4b##vR95g zEaW=AS{{j?d+-mEBExSbw7igT4P&|d9>0H3LL=)2xL$XJWn6+w2h-O}=sT|Z-qB0g zBG)&^W!OYObT7VHT~C8t_TL#l4&4icxNP|WP$*F8jX*Y`GQayG^U#akJ`s;AUXU&2is->al3A`gIKwaERbJ6klf}FOqs4X4#em z`QSLUk990_Xyr;S>jnw1OY*nnq&7HP!q7R%a@WdaSsnXuFrmTZbF|2@vAl7R>z|iK z>lJw)%Llxqt|xK5ZsF1)*Y78VEzAJZaxcMht{MIJin+=q?jsyI#|#&jLkC&@JfYg#L3K?z!Dv01{v3H z2z|^JS@r^#Oyhn+|C0o8>0s)Z9b9*D>0t(*Bn&bm%#d6@LkK;~cE2LHeoMe0VenNG z-es(RF<}<7f(bLXGkcg9nBz?GkO>XUc}$SGh1tXWk+HmH!enLz)6Lw=Jk1O<^j8z6 zGRv5D=0@fr<`9F|O_;>2VKy@lFn?qW!zRpQyv$9^&zZNG(l<;vooQxnWgcZ-W=wCI z;9`8t*O{l7_ZjC~Cah#GXC7pJ%skD!!hFb-9pyeTtC6@0c)wIgMGtT*$0vzRKLmJi`2iDS6j~ z#mr`AC-Vwpe~ne&+da~<<-=7-Ev%qz?%Own-@ zW-*JIOPC;Y4YQru!#v0Qg*ndT{*&{@EN1-wWIN^oW{`P@vHi;g7qgnVl=%j;m-z$p zFQ)9@Cd_2cWBknZ%!AA`%u(hOrsjkRpJgs)HZylI`N^z`y~5@8S`PrYM5~e%m~4Z>tV)SFk=tQcphfF4l{_%sA6U^XEQBKFLMXe z&-{it#@Hk?W-!Z{OPFrvX66CrS>_GKXfR_Uvyf?Hu3~mD1I(+;2aM5ZhLbs!SkW}am}U`nmrmT6&bWOgynGw(1an;EAtE13@F z7Un+YSIjZSZs*vUiiHXUt*d z-%L@y88eubOpv*a+08u5yv0}w%&2D;FsqsM%&pAh%v(&J!;B?N5A%KIWu~~$j73a0 z^8@A&jH$?s2IdRQt;`e5TTDr@8Izean2VVRb2D=vvzPfbGt5wl855YLOc!$_vy=HP z^FC8p%K2f|Fk$8n<_YFa##qL=XXY>~nKtGt%r}`wm=~G%7(+SdlKCui5pylGn>oT5 zE6kYBtYz+G4lr*rrA{*%nE-P;^DJ|msj4*NY^Ig@I`bs+cc#9|3=i`a=27M^jIG*? zdCWTIPUct431(`I8K*HGW<7H?^Ic{i^GD_r#yQT6)0q~ggZV1+4dy}SN#<4NBc`^N z<7d9iY+>$W4lsXZa_Y>O$Sh*kF*h*}F$bBq8FRfE)0hjGE1B)gkC^?;@0ouv#_?uU zGIJRZ6JV}n?qGhvJk7ks9AnHA%$UxsVy0!Rf{Fr%}`Gl$X4EtctW-ej6nCqE4nTMIjndg|J%tuV+G&4TOe4bgy zT+iIe{EQi7US{57PBPBvoFirdvz$4f@i9HjRZJiAAaj6ujd`E>gvmX{j7nw-)5v^* z>1M8GZe#9c9%7zhUS~dHie_+MnI%j!vuOs~GCyGUGcPm$WXv5_#3W3{6imfuFb&gj z3T9v?X2FHoXuuq}F&Fc2D(2%fEWqhF1E0m`a3&gY78YU=7GnvP;%qF#a-4&6u>vcx z3g^Lt&to;#pb6*W0$hlT@CAGk7voF#GA==?9efve<9pbFdvGuA!~OU^9>9axi63AWeu&+82oK{C^y5d^ zgCFBj?8Q&;Q|!ZIcpOjQXZSgOfnQ<(Phvlw!T~&uXYecz;#YVM&*Rtl4PL-+F^Cs& z2ruC*E9;!k)Pui(#k6@S4HUc+DUI)?EE-o#rtinnnL@8Dg$hri){jNtG1 z0RO;o{1gAezi|Q|;v@VAALA2zijx2lNn{`+naE5zWFafr$WFPGNBLAh4l1M~Dy9-D zr7|j~3UX2+)pQMAOV`o$bOUXr8|fyxnQoz5>1*_L>Z99e8-0Ur zr*G07bSG`6yXaf=ZTb#K=Ko8PR`T^~tAJT4mh#sa#sGojB zd+5jXDD9=6&`)U}Jw}hy6ZA9sIsJluNdxpG?Wd>c06k65(6e-qenrpG^Ym-_4ZT3W zr9pa;4$(_=n0`mUr$5jU`Xl{`UZz**&-5z&g@))g`YXLo!}JEdNpI0ndYg{XJM=ES zM}MRDX@vexAJ9MOIQ^6UMgOJ~^dWsj|DliR6Z(`+5+sr&$sidelVp~1B#UH~Y?58d zmGY!~sX%f_g;J4JER{&5QkhgPRY*>$QmT@wr5b6RR4dg<_0o80f;3T@Bu$p4NK>WH zNYkY0(kapmX{Izwa!IqL25FAumgY+Hq*JB&(rMBH>2&D~>9f-3q%);P=`3lXv`AVk zEs>T=XG_bZ<q9O=_2V1(if$Rr7uZemM)Q+ zr54F6wMuQ0Px4D^rFBxf6p+?S8>9}YQwmC5Qb@W~3QOHmMCy??N|#B!Qv7es@^y5e zExaid>1y`+y*~cmxWY?S7xWl|QJ6Qz^4?5$JCA zZuAB^ysaI6eTxnLO`;bmwCnsqeO;%&yW6|Yue5IN^!Dmo1w%cpX-*LA_P6P&W#ziI z&Sq~qWvhQ}SJ)ryOraK8POokDu8sJ^X?$qYoTXU?uVV00YO{&VAIvH;e{f8ZrI|3o zB-M-&YB6Q>m6_&@FiSaUgg)b}>5h0K{$zu;c1}UUUwPT=&B8_uZB|CHET^~j2eWYL z501rUz#mzgRd-~=?D`~IjzVtVzSBBA)(uE6icmPv8HfZnYJF=Rws!R<9BS_4gh<>E>&iqJaRqa^ zKirihkN*wfNxMhP*;wtzbdu->JXU)(BiRS%_jYd@i|ttb^Du|JfpE6wJdehdrqNf4 zY}*C9f^GgWovAD24~}_Ma@rj;%lXjah}OvgBISuHiW(U|A9+-QtbTW<1y%EVAf{nv!%D-94?k>I_*-*-i{{a>MrMWm#X!)nIodO*2kts3)xfPyKZ2uAYd# z1F=aa3$jS~mPDM~DwCQ3B2f8D?$|GHzR52Y>DATu%FUyoBiZ+86?fOe;m&GE~ zn2Y(FQXgNA8ExWgGNY-oFf*I+>da`PF42r;S@u&&U1o2*@>1JmmG{ve#B9`)&2G?_ zYSx9Gfmj%640vUvQH!OK(qg`@Fhf}LGek8%ZBX+w#gyUf8BU(|+8=MVbBfi|(a zM~j-pzdn~nrEVS>4dk1$EQ|udG)Cg(SZV|Df-JpW&PJp;21DIyu zw0HGdW%{&g)2X=xC+AdqE{#-tyhs-5c+h;bNLGm4CdoA&N!BKJq*;7ONEYb_rF}WB zRfwRHEjpN}~(}^_0AO%l|B#Vxy<``NKRq>Ma#d89fsgk8Z9TkZvHU z0!Vk_cK)9jsJPEm2L9fVH|R^PjfA~zkre7!*V5?M`IAm9#w&Gf!a&59LYq1^?FW=J zdTnfaEt0L0m*j@t=C+Q2Kgd@ie|LAFD=0ULJJG!J5Rzmcsoo20NcC{PLI2rah?7mj z8~x!_0SfWxQ*;IWkwB+k{(hq)YEESniGow(9=X;V5QTEAk$cgXwz7v z3_J0SY3B1}?ufd*W%eZYxilu?bDOS-n0k8c(+7~|yxP-+E)!R_gj%z=V_mcOhlXd* zNv-qgDt-R7-ky%gD2-^MFHL(wA&+mv>GgqN3Vo-)vqMg2v+{2fd)q`_)0*Fnrf*DQJ9%MXQrXGa6-QAb@L{O;>Qil}3 zUrwcugi~vpgS_2#^K-haNNpyTNNR%&0ffT-wSg2p^raAISXV-kX%YA`tpeW|mVqye zb>PclA^5Ug3BIhCf^Q6K!I#Bi@MWJvp4Ch^f9gK;33jd4duHda~8rnK#{4Lxd~ZS)x@n_jDIW?-szW9kjt zkEu5qC#YU4F*&o1Nwv;4qOr_ldF#s3OtY6}+eY12v$P&d(7O9A%abMY-G^41u{S9K zPZ48MIO0PGf24^dOPX7~-F_XhaGWHM|6n4mQn*cHk;NH=G?k(FjG9U#g2nxE5X zHR6XdNm9)l1&v0$Mo5--dfRkbr28$6u+aXZMynG)aM72h>XcCH_e?tpw5rU%pG{+{ zoGu%?Xlk>u<)mhBn=#GV{D3uXo#l^LGd9rA%jjQ$Wwy}F@GQ(Z&tovP>^ddFhi?)Uoq;jy$(zNLnGIy%N?-`$?2JrD9& z!cpf$md2w8JIiKc=1l9!; zkDHUU+Pz;0wReYFnQ)<_N$X1cO-ZXuwbZmmVslJZgf=v@NONzUY^41Xre`81WjYhh z*RhlaX_{vfscID3kVe_<*H5x|(n&iIA@MD(nLEq-L^>1UPS-?yc+*#Dcc5eg@zrOP z@-lDO*R5EnUsGGXk+$}1Y@#EQmF?(hlrkGBbCA??z4ND?)5$?-Hy){T!&`Q8!Zr@ zUPg)MG$aXh?dG|Y1j0`JU47DVb8FAq(RKOi=nr=Wf`RTxpiQG~>*(tCYb1f_pC#}{ zxTtzmC?Q?opNo!*YoVxAYuPu)7b>$}1!m4RSf z*{P%%htSyQhQ z^)p1dSd0?_M3f(h(lSRat3^3elnX`a5oNn5dqufblsiOuP?U#7`Bzbni1H&*THI<`Dauns z`8iQuB+9j-+$_p%qP$y_yF~djQT|$#M@0FqC_ffu{#>=J5amQsxsFUl>V z{FW#m73B+}91`V-C_fdYW1h&XD5r^Xfhbpr@{6KeFUrlL>=WhPqKy7GmzK!avPIzl zUlqL_Yy54>r33?p6@KqVf0BHiVR?{6-j2ZKNy?i|YdZY?5MDN25C}(lyd55OuLF)m zB}?VY!SABAvy?p;e~H%5SGT-l(%JsVnoZpif9LYx+AjPls$U^%&t0;5)shu+8kE1@ z5)%xn;nJR<5`=5cJe;-og0no!qZTh2S4TP)c|(z&uz!*I`+EF|W$dkMLr*B$kkb&} z1iU6|V&PmC2>O7Zna&TYTZL~)Z<{|Pn=cJ?aN2+?Ol$m+lbG{NYU=e^|btdxLGF_U8GH@X<#2FN+Thfb=VYwWuJg$D<(vF_)cI6ycC%0VT z?T#!7hr7bSnWiz!?t?NHTd740r(aL<{Q@#9AEtuLs56QS3jN1Kld zid?3B+i}b7)$h{MQ9)~O&Qzx(EKKI6wrX>E`kN)R`;L2i{ucZAE%;(OcH-{i$5oB0 zuB?;!=J-O#PWn7IfcSCzH_4GDl-JkD!Yx$yGzJ3mOwr+go{yL%? zXzhzh*O?P}!d}DU>}eO-RbN|s;fQdRJi{xeU0&0G>~78YF03}{TE26YJ^#BG?edM5 z+6`-YYg=1PI`BZgB8V(E$L_3A>uyTHo|oGCi8WO^i!Rq!ues^8ur@7PeF;vqeqgYD z{-E=PLvs<^@;NAa^-+tV`kMH3FXMFbAI<3#Hap7uT{l6j&;v#GL zoQgw4?DxNZ{=B5vDR+I(`@vnt%5OP>qkr4^p}-swLqtr6-|V0B`cFB$KX^Fbgn#gm zf5lO`{{iEw4m_xO{K1FROsJh0K9ooEq{9wxJmN_E{mr)+HG0dfwl3dh+wI0|zr&8f zop#=3?5?}*Ua`lX@~=Mr>+9m*wM-0`r}*oyV{Vbq@kboLob$TlS(`2GHjleJKU*0% zCSoy8{af3fZ2O^`d)%iYR(*$8|IGTEJG_Sa54OJ8x}?0+I?%e;54V3zi)A|%ktg?k z(kJ^pdGM3#e7F81{mzkeS>!3rk-)8g)n~^7NhM#g?4?3^k zbNcbVbN&ZTzvpz><0`i4o6DwmZkxe*Y?|{quh+C0Sj%Q^3!B+dPWggjUuUM+=WRQO zJr0Lo%=u4$_ce$}*>?7M&D;I5=ivXxKkEp2MXn;g3yUNV*I7`c6c51qbwvDlL>UyR zz?GZqD{_g}f%61TlB~#$>hLg<$CYxc$RMss82;!$CW3L0Is~41aT8SCWeIYJWS7NNCeNosq@<&g;N$X zWQIDtU@=3ag>&J#OB%9>I$UlkL;ScOzCp_I0$getL-xjf@ES514=iiQV?Nr&^YFYC z3~APO;C3q+(u)V-fh!x5!^#gJjRataxNN8#108!{TtLf;yO z)Zogc*JNC{a$RyR9)Nq37_NMpWN_u#Ytsi@nIZ$Y@@_JO=V0kNh7`9IS=^s2f-7Gj zrMPm{bqxvN%0oy6uAD?_aOG4o8CQ-N!E0Q(FUjB`xbudF^x?`?M;S5;S1ws@$hVDsbhwm4;N~%A3hlys*C^dmPAp!9y@iSo0PK zNLK5>)`JY0foI?<<7pQUz{iQFgEa=b52inO23~du{lQImYAy4FN1;h*-{Jxj4GB^1 zg}0FgJO{Tql)m91xKSN_!vpX=G98zCL-r#5xN@k$kU?Cz*d#;d?c^T8N69ce57#-& zu)in37UHK|xl5xVV{l~y8Hbzj9isK+2t%Tid5>~s`LVW#;r&GGchcw{Ig)U&;aOJ8bjr-wXvmrO);R_Af`VvE4)N|pe%M6*V4rdYeuf+u~ zH>4y{WN{a=Iv#>$CVjxOFh{tL7W0lP=V@i1Q^yOpCt4nYZH{N)pySeJ$Vx=r4~>{1 z5j_{y5&gW2z$*!L^f!>~MXWaA#l&h8)^`{Z<=hA?@3cJ#n~8~=@RqnCaqT}WkSwme zE5Uuim9LT)wGT-{y2v1&f$tLi?DnQ8CssKeB3dqK?thmd^Cnp*u)f<6Kc0uvdJGwh zXJK`QdB(%=j4KS8to32|O7^Fg!;-7)I(|5Onq9{a>xo_~3QxY;IT!X5EziSo*V=su z!(DpqK7`;$#9GhS8L~J@Q?A^B^y13l*BdeuS8huRxbk=+sUnMKkPT*&K8N8IM6Z>FFFRg< z<#*Y2g0PC{y$;=N$l=8LP79M{Ds5)qbf-KA54wjrr(F3iiQ~!z?`6N>KDalr)*Eaf z%(KPdeXJSkD0d~ZaOGZPHmqjh0ERVta*5x<5Ad0Mo?dQ@B>^6SBA;n zcm%HbpmQ$VgVa#2e4RAn$`8m?JdmRgM89W-;UnY{%JVSvkRcgdIn#09!-i}{w0;ma z5^D}&uT!3dA2}|MFm}?%xyrpsKdxN2pE<#mCy-yocbJ^~L^UUqCuIq&#IqsXs zC0h||ZsFqdx@08nD7Tx>C1Y{rrKAxz;gh5ZS9Z?t5))VM?R7~nuDoPHm*jBeH6)K` z;g~gDQow_7!?okCayFY%o7a84CWbrjpfh%|0$R$&8Wi5%}$`v-{y14SLEnIRR zuIwW-@f^Hvlzpu%OpUg$m4SzEX^j_BzLiU6QD6B9@n(udwsy%q#D^;{-G*~<n7=9X4bQ{+6M2nCVC6~76&{B3o$Qi%ucS>l*D3S?_rg)9 zb1ggwXAwQO03SQYB~vKR!=ul&&n=wql1MZ62v^R3q04@T!<$Jz<;vqPa>;C5`TXTB zK9hxGt`|p9Jt6oN%)}mM~1*;*ucc892|aE*Xb=;mF(U@<?c9%@X3-IteT+)n3 z;KFy>bLE2z^s%<}T$m0ZYzgSc`PQrye9U{Sy=CAb$Zy0u%%a3741 zaZ3o#z#DdO%M?5dgF(0by8|Wi_81FrGt+I|ivYZ> z)h$ER$-xH`Zdv3y98OBp2Rs6|$hf5f55h&SU`}x5LDSq4#g!4#iz}yJ@0LDo2cCK> z_X{`St;BnMkxYj}g!O6h?%TLul-~!RCD!j3c+~Cmhw{nrRk9*J3+^-BEq*)%GlcpU z@4Uk;BPs8LWA3C+xboP$mToxr?Nq=Bp+6SSbzIrucpTp9_;fhKapmSS zxbL(Xf?<-yBhdR8dq=Me%Sa9nz|F}FJP3Cp{rFUvBHCseen_-$v*DtT+vO$jaiaID zA1>SP%pu&u@zL-w#~Wb}(RQ-%5t8Rxd3g0q)*;>tJ!N-WU*$;;Z{kK^1 zyfZHN>gVD5FWTj0@MzLNc?5P7Kc0glUt!*HrAb(a7M~`1twDI$t9E%K%#i8S zS04Hr&k$`Bj(puM&A9R;qVv!MUvS(zi@AM+Ii$`Exb~ZN`3QLZTW%Sk{6<(>u&!%y z&9~W0H!(l(P*Q?7z%Ae5dU!e9pICbe9^-ff-r)F+aM1DDaD#W*!<<_NcNpY(hzH@R zWDMR1Ung3B7M$(4a>MuRK97b|99KR|w9X(be&2G7C5|h%cRUC~jw>T1%5{~`5^XaN zkNUt~Gn3(QA2ILLnF2o|dM{?fl|FV`-xJ2dp4sdp>h!_`KXF@sKcyO;M6^y5e2`eb zVc`OwvZin5zQFBC7!ShpNGaY7KOkf9A$Z4U%%jc^93ZoB<v`gJ=We_ z5!MkcZ-Cvzdd|bC#U44Au_$K{>R4QIF58E}{T&|%uO>Q{UMO>0%DypHI8&%yVI))~91M_wZ#+MEU7Sj`?+0eaW+NHyik z_eca6zemm^+P7vnjaYv@3U;l{YwBd+jq7+MhbuoI=i)=KY+dXATI?mP0gHo9`E0n_ z2z$;~haobMr4HPAJ^FMjeTE~}C%Ez~QjDJq=ik6?(+l?^);feIl-d260-q(;=RQ1a zBYW*d;1$IB+=nkYJ^<(6*x6I?7_v9lnhLKcetq7;*PS}E;NVD)OrcI>6OX*VsXbS| z%{;Oj(LES}r2(tH#dC>CedUKl=fShNN3J6JT%86t*}@)I0IoO6!}mBGE4$KF|1p>2@c!dqrXQiCU)>hnDR8dbtm=< zJ{|74vqzfoyrRDJccJ|9B8w~R%A8YYMYs>Kp4IS4qJ5qTkK4_jpDAz#k=u(b zPTrk+jo$}Ps$kxxw#4;CywQgO|W7 zh_-Vh{D8zMAA(2K+w(jbK0`8;=i!Z$m^iDcn!Rn=vcCFCZP`&FPdyWyDowA z9nEJ1^}X;4qH{hC9(s)P+=lNF-yQS;UU{tDw`uUH2y;kz9tMx|NI9+y6Fyrl&T%~N zQSO6&62imq0y3I*nqm8i+%L-G@G+wO?1%3WYhS~LlUPI4QJzDr@0PHgXni@^BioZ0 zbt3RmqU9$1nCSD++vJf-ot+0zQ(L#kgD7GF3(`bD0qHFXy(=tb;! zDM}Ls1VK7TmntG%N>EWkQQ!ii(gg*izmxFgnFRdan;T}cIA@0aU%&s}d!5BhhID6n z{e#OYN}fOZDdnc?6W8ykZr`9NHK6cIw8j-i^;dR#2_nZVY@lubvf}c9iKaF-r3iWzgm`?bz zsIzZv{X#}2a*o%?`rWdCWyY|6R)a)zas{dW(lrS&jpp`?KGPg~bu5K1;QH`ndbAFY zd-NILc8_W@CM;gno%2*kFbfag=oaVIo{{5)p}$nQ&T<*h)UCX%=j5uN6Y#mKxwstr zX59T?U6z6%mu)b;K;=t+zSV|P9%b|6upzcHTs3W?C7f4>47^*)qu6cs_aB)(Z9c-q zCG9t~YSeU8{!maGHpyFI9sISzzxW2M=}9e3PRzW4(EhfIMe4aIw#)4N3~DIjyhtnc z`*b3+V!_8`b#8~v+ibi`zf4~=aNzxrZ`U)%V^PHh*Z?Kq-#5C)!lMt2mO64+_awc} zJK4URm2Lp@vz(0maCIihn4kHWsm7Pp0WTkJFN3Y;Q_n=4{!Ymkv3YPeH2i*5b5YBO zCyUl+?dDF$L9X>KD4H~Zi_@X`S1#8v_%vO7Vnl_OSe zYEbKE!AM@z)~mkW_^OwlUD9@|YhV2&z}am<>&bCEC278@sC=(1r;Oxfp}OLWUlvdb z+|o`-dSjlOH`o#nTLtKDxuqY2)KzRF#_J@_(MGGSpwUFw5wuIt;YBmEBOl@xpQ;P|s2GNmskL$tic z*dpC78yc8+ed8%GkQBWny;(FbX}sUKN8UB~$BYP@?DK1p;W={oxh*D7uMVMnZ8oHy z-_cb_&vmJE?f!*bRF-S(qtDOJDLgrAK9v`izj(uBq_%MRZoC!!g)Fp)-Ox|nl_MPb z_fD{JMd31W_D-I8{R!w9C+zd33T<=u#0rtO7l)W!!phV>c9!dymy7g1a1|=k>SX)T zyk4v#%yOu?p;%M+Boz7RlGKB+apbLsWdR?9W;T~p0*VwraJbwn)A)#8(g`S6>`itR zD}&vsXzU%Cqs8o%KgT{2si{%cIQ<%flJ{U=i9B})<1Zidc(Y5zt_b>pbv7KME|2Zf zu`7r6KAIE8Xn$f`Zr+$zQD8aJ+&HhPa8i2gk*`#8*w?XJl{_yFST&^3@?5{G$CVVy zlXd_arG;XsQdQE|)a*|Dd3K{s1@iFl*+#8nV8v0WYP;DUk#UhFT5Xo|0#Esor^aU( z!_yOrB_IjBEex)6=sBdqM!0W7rtS_)T!`ptmvRR&{PogJpzeR6%BeeSAOTTsvmb+ooo<+QV|ga;4x}!MR?& zcnq^oKn<)qXfR`NbGBqw#mCR5s3uMRgXJLmtjlyHM%qiGCb0%P>+6$QQz8Fxu=nxQ z>|B@65e#$nooY3nv8d~zKbzOasOM9C-P3sV6Zm1Ve1gY&?zX5JrpX?I|KwdgzH#?j zlU|yPX|%BJgR>nmjBS%BWQjn3QaE2gOi!~-`^ZHw2&1m?G zd-_MjM-l4g?V25|Hj>=V2#mWrt~Hy6Mc*B+1$Tg(!u{ZCa4$F#ZV2~;zsRb{D$J_0 zdt#TZQNqD`GzwALBrMs{=~3E{FU5xCE$t6athG()ccp)L-qsza1#^J0I%TG1RA&@t zHe~kBY;d4&pot@_VyUEcb!A!Xj#=18?E&qN z?R_?k=pJ+gS{IE)&zBFCzbxM@zgC`FK6*(jU*aN@&^_a(Tx3LX<|R*Ij;V;n=2awh zaq1;-URf+-`zp#yssxfa6W3OK>WVH?DF@6nY&^elGE)8G6;F*9Pb;1lKCMGOL1v%# zSofAx4MYbo`4@@&kHIiY}QZuv_jA_sG z$Wf><2Hr#E>g{5?JZ3W4Vcwd0h zl4Xb@Gontd&xvv@?QVzimAzN@N~WbQ>fh+>~#T=AttM^6uwJEYU!F^7^8eGRMXTTI;!pF z=kxzcp3Il!%jTN%H#G+E7nUkNMy)ej$%I5Cvh6 z&`U}`EL+0kpH*;)v6yMa9T|>ELexx+}qY zE^hEDA7EnqVBAeW)YHK()N3z@i5A4pbY`!cL}a#`jW$Z1{oG?7$0|VuF6x8(_FTT! zC<8ip;3)AN3H?XAHGSxK-p z5{iI=A(Gb85;D>V`P5?>K67~nMpQ*f`))BH43KB5k86+P!rN!B zoIfA>HDM-bb$zz4S1$PXis1K-JI7ci(I=Kai2r|`k|o_fXZt~0*7sWuIe1jWC+A?H z<#}$pbS>B4a#Op4u`;3$Gc6@Ns6eINiJOAuOVK{hN(Jdr&_2v!W#S~=JtOK1t*pl` zX&feZ%Jo<6hy{?O$Df>n%1G?1uczAsKD_spva!X!I}BqM7F}{qFur~BDnH-o@V>Ju zrE?e7iTURAfOSuD#_cf0toFb4!-k%nc&2@;fyKhn`U`U^9oJ1=?L2kP$jbt)?n=w- z!$;j9YXNZh&pk zf3i*z4590U(Km|Ig5CweqZrcrLcp!{f$5q#)!F`AzPP8%5nOvb%k&wtpO|}VaPo)b zf0l#B$ffZl>fF1}^iRpDGE>xJ<5dh zNec=$4AwIajm`e2gBk>SNdr0r;sI>MzfKdr6V9-!o0liP!XNz4O)3y@zMA4h&@?zI zujHy|Um(8l%_79@$$vjG=&AaTiUU*O#}Ts04|G!F3j}d;{NsaEAY{Pw8h&C};48w! z)qibAQh~$3v7h)R!cH`sflR=5rvTn{QjtE%xc&Zs2r&wSLI~HSBKT_0B3>Xb0}$ZH zQ8E#FEI9?f@{=kMG1|{I5ilw@8+Z7G#~2VvC?sN>AXC8XqCm+3Dk~@CO^o~Yr;%{{ zF3<=T3t>%wK@S+m$yC_8c5nd2dN&ex)z<_9+3eOGB=|aP(_z>}Bw-@ch}%_zlEoyX zkB~bt+T}Oy%5s-K{DC>Zfv*MREGlnyumA;YHm^9gT?#p4i=z#kg|Z>7YGMs_}W_nOD%LeQnIw* z;QxD2$k*k>yWKP>S>ii*2rR_Ndgv(OdRu3Ek4YN^>jmnG@(=C-%83gNh>mRi>$Y`% zw~VA1A^wxo_=2Jx_>F*3Ipuf61-K@~*x7@UR;$(zG!z{NMM)t#WzaK2kU%7CM^cHM zT_~vpf6p!wltx{UQYRQgjICZ^5~F^XM)DStRHl1}3}sm%qWD9<6Hu=Inj=I?6!PYg zR6_wriGtUlWT_OeC*)3y@uG$#EWZm2dFMx}^K~~Jiqb-)x$n6^pm=?5J5th+w|Jx~ zsNP*@02NA}y-Rlq`4c0Zme;O4lqkvzk*7}T7l8-0XFF2zkoR4rDk*&nn;y&`gh^^Ly75+T_y0eqqid^4|(H5sxtcr6-u63J1il8 bVwCEt{14AQ8lX0Un1HV`S`a940Dt*EbRn@Q literal 0 HcmV?d00001 diff --git a/voice-natives/vnext_natives_win32_x86.zip b/voice-natives/vnext_natives_win32_x86.zip new file mode 100644 index 0000000000000000000000000000000000000000..35522e1ec7b3fe1b1b2a44216281731b09138f92 GIT binary patch literal 411626 zcmV(iK=;2;O9KQH000080Dx0|P|u}UQCCU>005Q+01E&B0BmVuZ*X;UE@W(M>|B3b zTUQlN@1rVX$_b)((1#g>oLx{|FrLWgOz&&#V- zSM9X*=k{^xwA0V9bQ>c9B+yj~q)xilie23v3o2W&1d7D(IWIuF`Rn6H{Y$py-FJVS zd+)jD*FE>#=lSqHgJdum%=ni~8VoH4{jb3A&;Kk&gJIG2Pb@M#KL3|*ZZWR?<(qHa zx@||+_Pam%vAgfQE9;|oe&Q3KtjqeymaMz|pUB$wiLBM@E3)qTzG{eW=U@$DNO*3TvgEiTJ^0~Fs$7weH{rc~$+p@C`&#&a0c|bf@ z{D1jh7KZuGyEoricPHj|lTn}hyYc+Ml@$x{|2w%Fsw~FOKHy*hp4-!2T`&C3yLa6E zQ9_fE=gc@Xd?xL+@b2F7@lT@S$KRmi!0<*q>t9oEmEr$?|JI*Rj0j&=aHPQH%a+wU zK-?9T!f$V(Wf8rxA;p~#?hN^GdzA<*SKOL#TU6^cis!f}$dKD^H=5)&vr+Uq28BCM zsh$$%ea?Y`@e466GL$|(C?DyT+g^@LF9=RA+Ep8zemP)v4#aEZBVA%JGPJME zZtK|=IrBDyA(D{Op3gTJ4#?r1vZ zsJI8^)^^1gKG2_VbSv&YsYkTOhP;~eOZ0do9PBhZdk!d`QN?{y@r>-l{6%$E)P3GS z2-UI%cglCY-(&Qs3 z^>#obN#EXdG_C^jUyM})_!W)?bol~v2(?eZ%la3)F|dM;Td!Jr|Nr!Z%9;k0%nVmDdK!w67KVb{p}b4I&t;Z ze?1hgyEf@xv6bj5=?^FUXS9JdqaoOdq1c6IRJbz>jTpQ;1Ek{WmYYugC7A?c8Qt0{ z#g|3Q)fAaZCO2)oP5i#P0Z5$I)G&Sj&@oaNjXob>fc~ZGo;3GJaLsa3j(|9vQ zZrLY2Rjye5OQQOW@QjR~)mb^zBkz5fXw)|(x4tYq7P;-BxFr`n zeYNmqu8K@ZQa^)E^iKxcUy)u>{6nFO4R50H3!7SC7QH30NxAKqe7HwCZi6<&>Q3NGX^Jk6BVPn8~0im35JmzYbn|?A4Dy}{+RSy>GD0g`>RaZV9HC+`cU7&nT-(`fXaB$!HLR!A?77k@Qb#n}5LT01X+O zHp;vEB)kU34D#-kfP=}RIR^YOQ3^a*&`)&>iIT=kWL)h^YcWDUJt%s|r@=nz#-!Bk z3`Zswg?e;N;2Nx7;5L~ZBrAf|lP|mI8l-&0tjI9q7!{UHlRO>CS{=n5Ol|G+u{3YU(=OXdz<7tk5b%RlQ z&e81}++_iD0FTd8&2Iq2q(4XR=g&U`4xV4+91tDQ3F8-eeC|Zu^5J(F2?34{wbTRz z6v&4$dPjfKzf3j1-pj*y@TWvNHZ&I<&VliZq8kE<3T)puFpZgkXy-*owRU5Ma3?}x zIkb|n>dAUS=iA&iq9qtKhHx^uChA^hz~7r~!@KQh^q^QM4ue|%4q>ZSKdiXNDS;sE| zXG}M{ryyfOVgF5FxTJq1=|4|gm-G*5-@p!wT3&cqM@}Y?!>Dmy93Dm^P$)38_bDXF zP#AUm782)rbr%fPs%h1{z|lWrrpPtQ>g%Vswa>nlOb7pH^!E+lkG9lB-}h+(7O=_i zW@PCD`zZG@27};3I`=lb6QmN{nP>3dAbc6lo~V12FdG_ZxSr*=d40|JAk2;Rg|1`u zqwxi(getT|HWrsd6;aQ?Z`vU_}QpCK^-i)IR5O?QLX!-6de(st{?7zX+pLo4S0@*oXOZZqMaF1 zDqs@&wSlbQgl?X+MPZ@*M+_9XZB&;uQN?dL(Dqv6rw_VrTZCaJU{^Fo0b3tHnzebqUTTD`{ zMk!?K{u3k!>H@0pjbbiRFIYGDk`Yh<4S@Wur0M(`Xw$1T)L~|wR&~o6()XSz=P$ME zHcJK_H*@xy6-|JcOxSDLDQgW@N0t&ufcG}Zhdo)aC!iPW=07+-?dpaZ)h(b|pB;Zr zbS)VeA6V+k7>7BZu_Qd+x3pvYEby$FtCm0-WP*TSmfI`@1ItDF*l#1jpII8}X^=tj z(-(e3qB?+Cea_{ZlGVpC>l*`hvKKaIgJ#y7sIlCZ&O`EKf8h(ZCbJEu&K}P~`N)d* z%TM=5&drnCPDsZZCwTjq{scYZ*ELSiwlR?Y1U=$%jr_D{VNK+B^J=6M*tLN|+iV6R zr3H?OVDkEgk2sUg9_+ppG5{At()R~DOyWdr5*DFyZLrJia%b27UigT;R|TUcOjrqI z(wLhnNoRXq$ySRk*B-A{zmr!WWo|W|OG@bRoEclkZO6{MEoGKJpHKXA zEHaEV?eZ`PymAq5^p5m|lCp9qiQwe)t_94^Z6xGSas0Qh9`Cs;#yk8$)Vsny$94is z-ao1MtXOcS@XrAcL<3dgEXZ87ZifZ~{pn(`Qh=_e)XZk4_lVr~KDo`NTHoz>Wm^x) z-dT>UQDo`Tw%%9eS+KRfYs%=4vgMjU@1lAP{Sw_qOu@JjrUklFs>l3a-gMi>8QPp1 zZw=<-4AXu>K5~kA7lXP+eJGpx!(}b0Pb+Y>*Z*1gGhAH_OR!$vFFd#AB|_|&um6&g&UYZF!A{&@3}fz3-PWRG1sRweTG z2>U+K?s|3?D#9rtA2~}_V0f3=8IGIf*6@J?LG3D$82@c33_HFXn{a@zh!bS=9~nUA zd}K~zn;+-Q=j9_9%PVpl#EE>kmqbytP>Oi9r=Nm1Eb_u4mV9Q>1>O7L_ykOP+H7N3 zQM@6E-NO4s0FxNRSP!6pc5(@pAK*2$z=Y|gPlIj1cQL6yGP$Tm@v`_B(x;jF`+M?H z_^o77$|Mb|783&$j1+1+0_;A6*0&)T}F~T0CWe- z$LSgQXoP&MQ6M6Ne=_<#+9dm0E4t1RqQvP&Jp-WVDHo%F=#!A~W( zkrycVM`*})(TlmH$0m`CTgFe-#D>TR6B&}c+L5DV9*%+pD2ujVZrTTb=qTxWC>uww z+K|Nd3~rYVBo#4H?3smoN@`d0itrTGR;gW>gP|lS?*zGPw74lYbYK-~pJ!WXUa-sL z@(tAw5HorbMVKMxhOxVQVlHr*Tvky`d- zVCSr;AD;vqXb*KWC$cMOr0V_rl0)7MCGQ6E7<-VguN ztp$qO#JRUChaR9-`*(BOdirfWh~H=^j9=dPg|;FE(YE_M3o&{389al5JZxzOIJLnd zH+3Tw4IQ91oN7s>gnR81{OpdMBdbx_-;EOgf@r8aRYSEdQPiDyAq6Q;DQW@I(26{r z*z<6I9U7#Z0*h)ck=u4oE1`XOCr)p7bmXhMc~%kC>M`+>MzrtUE@92rir>bb7biuB zvOj?;ju1gn&8w8qw|PEwMZs1YrJ?Tq0uZTx7-6xY_&fA@5KGXkbFo^OPbz1wZ1~M6 zaE8?t1`*YA(WUb6NgeR~6kxwBLLcW&Hz*-0L&bC&TU2@YQM_uCx9KmB(aRrFFLm@X zlzQ1tFEM%v@lrGPlu$OMLyypJz^;TcDdAqOglwGuIM=aox{1=w21++SK)+{|hZ%hk zbh%2%&Xwx9!7_$&hZ4%;%offxPtqiVlg4Q1q140`HHWbEt#CAyJChY!&i#zw*EKGy zAuCq=82b=oVI_1cA)y4&j&m2@QYCadWfdEh&>kdG@-0M!7d(-~+9jJGVN&emb+K>I z5h-4Yy`UVja#tE7cDoW9<`z&p(#RV=K&%|-b=1l z)D<*jW`epjM?`V27J&lCgwona@YjPUvbX|`ch{Z5<8?d}oRAvQj?zgXDHNUGtPe^N zal(}#d#-VUER9{(nfFl7&YUaD8m!R}!KZZmT9jO)@Oyj#@>3{H(GYM^w_NOJp6GJ$ z1Y+l0?E$On&>osw=s~U!NkVMT5Fwq>Zq22`id-@20Hz)w zm@fiL#b$UEm|0?QMBOY#6_wyR#>IpqAziFg&7bjN+vwHq-p10NWI$b}P>G*V_-U_T zp+VZ$tJe_f241E^I+27KRmK#Bsu?uI4c7Xbf~~uGuAv0eI4zpKt_r8?<|!e1!aceF zB%x`Z;HPLlP7u!euMy0ZX>%4%LgL2EbRs`9&jg3ChuxA(Cz74OQuV)8qe+;6U|gZFukr* zLTBiOK@__#UXGk|69S8ok?+MD>dqanW3}}5gPYzrba(s zP%vK|;?&y3Nh!8)0t$av92%KLK>RAvN*uOcZ%3;le9M*A^MpE|>p3~}$IIv`q)|g2 zLDZc`bFEtm*TBorpzjf_-=;!cUQR+Dzg{f|p{$yg;Hjxm*09~90l3~i1*>^1r5|2r zp>9|{%DeaANC|zb_v4wOKV4fjhjnQVg`RhlE;7W5M(p5P&#?3Wo1D-cPs2jx()NgU zz0@v^N(tBau6aVGdIeI1jK!d~Nc4?AM{bTAjI3p*hqEZ5CYUq?%L)HAj%J=PLlDHl66)I66+~ifbO^zJ`7GzC-K)jL=|<;Z6+dnP(K7|CIDa^-`euB zWHZrNf5Mw=o?uCI1P}j-}xf+ZC$7drnD-(lS1yq zEA%mOmGM(a|Jo%zOS^TzsZNuOOZ3aXW87CxI^lvkLXV-^eT+Ul$D)~ zo00vZV6l7D%C3&6+Ik$`t_u&RCZTJQ&=93t??B0Xp21N%Pa$Hbs%oC067%E{u!<|$ z0^P-8xDxYWMVE&xoyOqbVI6|MSxndjD{5!YjZ9tf*9n!L4yHJT)2emN+;XKsrIWuW z*-V4M8t7OPjE1suFX3ix1^Rd(Gb?dyKFI*membQEUrfj7b@5Y*Uwy#v;|Oc(sA{(9 z45m{@vR}tEPE~bqaO8lOXJ;-SZl-DnQsiZ307ug z-n*1c_UXlNGZE0)MzeUHYlH(RX*}5nQ&(+0I6;Fz@2LfattxfV0_#h<_Od0N;w8RbSU{)$GDwKOLHkveGqm4}jYgGV zf=(fc1=1X)zLva!-MI=WQvBahG=xQpoSBmInS$k}uk#v~GMNy`6UodH3#P;c*%NbQ zZkT)(nb*yc%!79@$!wn;y7qbGpyw1}zYc}_W<{-5%Z1it^BnmC=S;op^&(yNihj|$ znVub(0jc>S<h+zr7YGGFI}4JZ++J*i-v_@^s7J!~td$n_xZ;dpGUseN#9Iy$Odqi!OE; z{pL_|XBs+exLyQsCN|$&UZtgPWI9p;Q?Pp7nd}othyV-|_)N&``K*3sp>MLGJ*(+x zS-}A|_6sqbAe}eV*~`6Eh!oI17$*feLS*S444tl9SnjRR-iu7i@r}XGN|=M^WclZN zy34@eKmRN}&>-?V)57llc0tY~3K%Iw59l4<>w|=->XR6nCl_U8e#M?w{24TxGU3)j z;ZLvTAuOz{sM4N!N$<)%6$(?1S3COBZ0Eg6_b7!MNf#IP^j%I5ARuClQDOd{w^UOjufW>T?NTz_CO9ijMMF!iy!=7L72tU|`hH@HX}r z_D@TvD@9cFR-inlElg<74fFJZca0kTzrzGD4O%w~jII@M-#tld7Pq9_eTb(5&f5lo z^9uA)sU1XXP$Oe3QP|&shCul#MtL?+{Q@9j6${ZWGIXt1JN|ugb=h=R7mfsS&;sF7kNSD7lzf5ju69s{bC`U>F#p1+Kz?YJ{N%v|6JW zdFYp)Pc4IA%ud4<>BIyjnF?0(lF`3}S3HBy7p+xV76b-yCr=gZL*9G%Ays#-7hG0r z1T%ZRsyoBW(?{y0w@O=bmd)tkC6gSw%SgyR?;MD_rwF+;vc?G-cU{^O7UszeN4w&; zD-;T)N$oe5(5VfoP?W>XircRE6JY)|bP`-^tjmLoQ*Nt--C>m5Zowkq*l!-r=p6l# zm#!}deL_}fKWx%5`8qKQ5fTp**?w*hqf{ZXMl1_t(6Ur$Rt}nFLCWAUQfmUGS7~p! zL?ku!v>x1Lk$T{jci>Q|7t@m4ye1GD&OY!CbkvMLSEJZa0mlq*jbSV(tx-x%v|RFT zf&nqYZdeRA!ZbyjMS79jJZCrqZ*BARQa;HnrqUYaS}rU`e^&X3MMP-xWJU8DBLe2u zm}*3%#!+lSbL6Zu4PR^2@#!9VkZNW?2DJB2C?313AG^f}q)a;Tl|4QmQ449}nBubo z=Z=2Dc}W&92W;WQ`Oc(27x=ggLoBni%F8O4C@zteus#d8aCj1u$Ihn#Q^ARhhJ`F> z(t=@4f-gE#_;O>D)Zgx1uus5h`=%f_qa1fRCbbFp&1mD}hfja618C z)Ck}Oh8g%6&Z;LEIBBSRqq7GG z0CxB*==^=1e*V6$(Dh9HDCFEmodGV_f2mUoOBMO&D=lh?k@#qhh1P%725B8=!CES< zxgCc{L6{%A-)@3r`MFX4x!Dp7TU~wf-VEdrkL;C^z)07Fcl+Z?AWJoW7z;tl@)`JI+SD1{exBiacyR6lvKDU7AoP*sKvG@X39?cNHs@|F_=R%%~=j;20@sZ)e0LfIPf ze?UI8x_7VS@B{g%nWLK=@Y6f`;+aR&Xs=-Y4KXO?N$t)7=*(}muUXm$ej~agf=Y-8 zMS_5oq97%+6AmWV2}Dgz5D}fYu{cW<)2S^41Nj;t{gw>CrMnd5?9RqH2sqp|AvZn1 zBG!|Q+(E3`WvB68EMU?Px|^z^C9KrGOqR(y&_cGuGbWt?0HTAdbxnz7VLBiJ@j%-n zAl8=+k^>U zuedWXYlnMG!f+B-5NTAC693{ve*l;OxX_(3Gnff=RZ?+h$v>CXGGqTsK%e~cy!Rtg zz%`21#}XWK4&>vA<`C8h$5g9~Qlwu4DnMV$UGA*)JT9o+D6@>=;^P>m_ zz+XHarSI1(%%}9Ef6G zT)#AmrSiWKCp2Yj*J=|RQb+L4a7uG#g27?G=CYW%JH9YwYmmIzR-7{%+^Q7kL=tw0 zo;4(TejhJI?Lx5LF>y)s>1}4};|y}9$qf|5LSEhA5O`v$Mq0gKnxZ%8c(NZILquWf zm{>)*w(b;%SiRbQ$-(kDdmz-ZE5#}b#aJfp&cJyeVmPDj5#21ZZdAY-ZL2p=wAVey7PXf#9=c!K6jr`(5rk3dQ9Lp2dX_R{b1ca~`4Eh|7jMHK>_gqYYQ7<~KSAB1388<3{%=bP)!W_ZTFl z6m~_agM;l-c#X4X>9ek=YF;8AgnPSJ>UZ|IqDZTS$)#NgJeS(x=4HcW3ehCMT?uCD zx+FKffe$mW2N(o8fR;k3T}O$lS8f{Nz_2XCrn(B8xWXW^V~EZH#|9{P1ntO&&yHUZ z-4ugllll=eVI%6X1Sd@Xv|zhAo*wG)OTm}S!O3eIEK$A$6JLN+;mK=gj|*ivLKCx$ z`!yK3k`bJ0O#3RI9~MB7BC3f(uS~%SZ(!lZ7CN2bwS&P0dZsJ_nA(dqPTY^ojq*W# zedqRnq>)GLh~K^FJk8M&;f8lW2#8-hP9SoF1nCre#MexNTx`>1=^XBXWBL?Prb`hx7j{XT;8sKOk&ns93iYl>k3S%_KrsL-EQ?VB+wW@E>HgJmKRTUyX zKUGn!{@I$BxaRW}+B;D50P5*m%3vZrkk*pUJ07H-rW7pc&}p4e5ffU>wl?~u_^pxH zIodGLh{%rUpL8IaoD3#Va5_gAA~57g)%0b`0nQ%LMdsVs0gm2|u<<`7x$ShQZb1a1 zjIfT9X%wpF+yh);L~@VD5)_U|S}|_)e>=t96ipJQ$b%~F_v_}uf?gZ%;?4|?Y_6;k z{;V2^sT*rT7ya1?euq?W9g}z0nc1+UIHR(1?LHqv;CzAc!Pccr!QbpfCvcuC%6 zd6M3gYC8_#Rr@Wx$Y!6V+-$pIqG5166)gB01t+P%su!@KZM~wn50Y247yLc2oqrGP z@yo!fR{gxqbMT5P-9Udtl$vRyj%fHPTKF!eqeHY|!QrRp+rj`*2&`q*W5O2 z67CMEdQ9J4h;*q0#+b(8wk?^ji-p|uZLVszeG=l$AukInd zccjv1B$f|{qa+smSc+19ZKtqT-y_JRwxd`+>Lc~4>96PY*OG+(I>fJth9an`nthVh z1OfQH-(B61ev}?@+M`xq_s2lmQF_32gJ>bFC&aS?4Qm#3_XGDiI1b745W9PD-@%Vu z@^fKfuyA0UrtOgR6o5qX-tPeWx?YxdXB$)7Ug9U!{8jw>l2^N-oVn_@P0UvmU!J#D zU9pFjm&vV2_QMhh#{1 zQyQHfl+5`nbzHVEF0CtdRJPDVNyn`=H=&bx_}jo1qCj~zgFtNXt}{luUl-a4Ih;ZT z_&25Dy(!#xK&nfpp0Jdl$jU*OG|}5D|vzj+T>1 zUeSIgo^R#-AAkenhPup^1=nLcuxRDbI}tv;v;~rs+Rf7+5Hd1#>WbE$&i*>_TP&Wxh>m&Y@Z#%2N*6Ip=c- zvZ0(p#O!QFB6ulHRu5v7bdli!Jo5{e%OOD-r~SFfPi3ni8V8)0;n#D3U?`KCGdjRh z(NH!LB<+;a-1uVLvr<&5py$`r(B60cO1i=vSU@w(qy5XmHp)<1^B58#11QqAzfUr> z`n(*Ahy>Vm6dNqUbuuAM-%|Hw^h-g2?mcs?jdYs58nsP%2PZ*2KrPm^oh*mk7 zj*>1~*^q?*&?cT>cxis~Q@aWHzx7poI)jwFO5=@&N>N4cBbPw#`!@7>d|pbwnACDJ z4W70jk%V<7PW;9EW;?BOCQ*>2)!*Z-^n$q6BXpZU3bSUJ(HUU}X$IX{i)~30*DVPqGa8~IL};wdP%{hk zZX?f|r9(t?@aMm6(!jW2^-80Y+X|=k5zXM{bo@b)BBk5ucfXnWA~DTpuJl`)tq-@X zHlqp`lp;fBsZT_(jaBw9Bd#v5#7UoRFP%7o;NV5m>~6`xu5o7%cCX5zfXgcSu+vG zkpl;uJ*wF~!WQz*4^u~}E|y*1#lC+ZzG`LY!PXoizlK`{Ct3_-OfkXW;*kAwOz}wN z73=f?Kk36y~?2Ygq96o`YjSi;D{gBI_MV2rqai_!eHs{c}jR<)0AGDW^fVJTJ` zS1S=Z+1|`mQWSpdudJb?`)sC8sFz;s5u0yiNrtn;JCNW7AEapZZa!VL5uj#f!o2Oe zkPU5Mmi)Xf$OLm}Ds#o>1@mcR)L`S#z|{H(W@cAk{aZx01B3VDdECBLISU;Z`Y3Tfl-45M_YC(?saongVP2YBDSz{o5f{4sTE^f&3#*QY1; zTUhiZNFgWqkST`E6)?XoJq(h@0BR zC=t)%W}Ef%!uSu21n6rsd4HbMk=Oykvw!}z@@H;3Qa5qg@AV1r+35aK8XOE!6G-t* zv_>SB^bz!81S>x83}5)su!Kxpt5+`(^B3YOp?6ie_Wr#@91j8U5Wu<)!DV{qX?@kn zo+k%`Za+uB@0TsL&aHrc*?ConRl+VajFSy$#1}7$MAa1Cb&jyafT6A1UlgRx5U>qK z6uWL~DJ4@bR>$>^3m$#bkW{Z;28nJ%0s9I4oeoC}b|Fwo% zgV$SDR#jeJS)u*>We$Mt%vG2?^Fyrj_daSMBr*clC)La+gB?>OsW>=EQA=4~wB00J za$Dvqp|aIrZJZgbi0V=vH2n})r9J|eKGvokRLZJXmuH2#GS{^+OdGD$n?P}j@=4tlD1~{$&p<-ym2vnj zPAILcZ*Q|Ihi;{&mmqeYaYY&|x?+wma9s+_Q(BqXm}*#&X^Y<_K^xLoaQ9^YW@4)z zh2IhG{ctHGty0lVt7aOFPLHl%2WmyLoylDsBI2PVLdPMJoj53*;79hgZQctGE|ZW*d)whSE0c2Hb3)1=2GZ!d&NFa?^cWMMnu$f%z@&%b`8V z8^{tEbY9d2ozl!WKa@>4kmKno2GRRa_OE5Kp|lK}bk5$;g(fz#UNIPZUOJnyXAkMQ zw^o?+;W_$Z=XCCa134d|E-Z#Oi07)bC)&t#g^~~_f}N0zaImhMCb~ZlW}BNI4{z3R zAqX>}6gbB4YW7YV>spovHho5`FjalvIM8XTU{Klg%civS3i`Nw(sIZ)i>mlMRGPId zofrEPFv#!A5r+y`euRkoQuA+WCi|?4c8O)$bdhAxTNXnsxh~WXU5@(X4mxYwVZ-?? zF=vwHp&A;Q#-n+2l74e^`>T{+h-9@(Rzk9!Cze;B6y>Q84^Cee1+sD3tMBhMj?f*4 zE3WWZDyyQrcsyj6D6)zj7WfjPp{+BSB^jd1EY^by>S@45b~-F7${;^O5&SW9pT7^= zE5&z^ou&KK&sr@cEW6+iiH7QCOwxeHJBXla$5wHOL!pE!Hi+uSu)Bs$P2aLOII~XXcPkI5%oMv>G)TWD_q`^_2RjPfDC%~a zaj_LQ-VvnDFCJ^C2iKbClcUIniv#lBFC*;?=NIMS@<}j|X;6xm``=hzriLkIi1J#$lnLGrsecUXHC9FgTNzp68a)2~2_IO|Np2c!f>T-Bq2Qg~PRC@7o;%!ok&>vMt2-E!}B<%G|7eT--4 zOw3H}7Q3VSmiYm=EOz7G+lt4EUH;MfcO?b6u7CZLi^el@}7@s>$jw)c_wrb=%{<0!@may znNncSQKLQ$Tx*B`9{G)z!y9H>qaajm(iBL?O!+$to(JGaD^%P(LC07Og-)HrX#b7+`$uvDiF7m>>Dg_@dd2%z12f7-#P7jsfV-QpQ zHTcQ{@g@4T&}xnH5C{p>Q!)26sBAf-xhUD`Ky;0P{;R@*=_&y0hm}Kg{sw+IIz+-{$zz@Kt)!jw#KHm7(hBTyyj=r|8n8GABXF& z#|~~WDVg5>;TFR_!@dhYTHI4};YWa`vdvTuyMvn}#PBf!)l7PhArE;|5chGsYaW>4 zgDZj)I5yI6MN||hc%Q`k6Z8&{aNj54qkf$CB}zp>a(kY9q-b?=M`?1$S}&5tUaGP^ zyR5vjQp^86DOAX`TpXvam~DsPbyH&QzfLNrV5Rh&^JYKcrP48*f#3)k?TZM)1D81%ZWvl?#15 zEsdQWzew(7@jOJ~JEKbADSSe$#l)v}bbdxkydj@Ha~2i;#~uBSm!CB3 zBQ%Zeb0*aS#GKWe5M!_b|8Aeh5t5n+JSD23Y&!|4uP@&>8dy#MI<5rJ=kScqfUwPg z$bAinJ~eN?bXHxl9?*iC5d+i*CWr2%mGNgn&LND3n6EffF{(vgB8Xtv=1uOPXgsFD z<6fOKz1r8(47#daXNTr>bVrN$PS-6i&jGj~{z9_;)?foZ8)!ezRow8~2%O4O_!F z3fM{q0NSH_bV*zahrOjSqT9e83w-9PIkZ7P5O`I4jy$zp0i`AdWiXgD$)Eo+OLPlP zbuF9J;t9HuFFt4%MYHfv%z;NxUZwWF_d+<$f^`) zV8fp@MvF7405RW6ahA3*j1fEqF0NFHvo*NNIUq)Rft_edv5jn#P2+kl9Hs?a0*ip})-%3=$BG^IG3cAwaADAnCF7d4^g zHUSVC=wam`uPM5|or6uv8IE{6UzY~;9EYC=s?o^YHN=S^vy5`+tdZuC zhoD9>(>MaxUd6FtzkCAZ&Yv)ZtRSuSL34ki3d`li_DPf9MRFsTRD`_uc5*`mM%2pX z*arm=h(X^k0NCY10<7~CGpQx-$@4-cmur8n=g-f98|dD@d(5nw_w%P`yU{*)SHg(q z{tf~(Dli*QBDEi9ctvIe%M!fvDUfRMa^U+rm%&T~qjMlBv>PD&9m8b41{0X^h(32< z;T!|aW0{?c9W@2$R%ZYW^r6K04^}wZEBg}^Wa_VZNC6y?I^)kpAqx%ct8lH(j)$83UR==?=EbtcWB+I4C;c zO-VuuN8MvOA$8J@*LR%lO-xIllTHZbRb`c0cMAsy(lR$xi4$a)1N2Gyx=)~w76j2& z`eNV{3|J4T-CKqw@oMsY)H4s!mtbEqy`Pl&$isS9pZfquyml4{>0On={rTd0`u8O*^FoSC}<+4Vi@md9ts zpfyuxzd3%-o#Q{gRuXk<`el-UoxYA2qR?iNWTC4l5r9?;Nqmfs@08f+_%nm#CE^Ts znnkV>7=t)e{G%awAj2&Btd3LkvD9ArBu6!(+Rm%yMZ%sTG9=$9A|qz~uZKMe_+T5` z4J;KAnlNeAov`Gk=(xO62NlnhjWteEME9tz$peT7!tx>c$C@J_S%=tq=IZX-d;2ERuO_|j#owGRXexr^~v3|!3#e5D`VFJ-_%vcliaio zZMI}A+bWB$3M%uWqNz$v(G*DA0fCgREjkPHL1gpAwuXmm3SD61dbnFvbY*Tnr_T4( zZIo?5(qdBzLc8EdX}8r4=Vht0K&2^Qz-)G7^8mAKLWtv&(ex^fgG zU2+HQjlV(9ghQHvI4ui8JsR|WY4|D@8-)Tr$erQg*J%*BY~T2=^F{Y4_&*w4 z$f0U7YhM~BP4D-TzHlgEXj-Zl8cc|zYAIn-NLHe{82@+ql>Y+SuX+v=o4kMRl;Vk;aeKCb<*{PpM*bMJCdZPNdJBNQV!A z?Y`e<9w?PXl)Uh|cLP}BX_&q6ICapDC-69vg))&vQ6`HTf<*^~4{2rd6ex{iW%CTo zLgr`*>P^e0P3Xxlq9-|z%{Nh09+SJ$68gBZ)WO}T*Q4?M*(Y1ysVptbK2gh%iE-0R zy@J+>_5^dm+Tj(hjv?D13)GKmlrkqnT;O9vZ?r(+Xa5=gD!!=y`M;q5F2HYoChcS< zZJ2&DX+`)e!5{A*z|bzpgfOgr#*jmd*5%r|g@%g&b>uxmLR7MF;Wms$$dO~nB`Z;W zI6_u-7*X*m)UDWCzDM+GU1^@HAFIZd&gcuW@unRM0A^iaf}yQF{%U*>`?(*~S?W~H zWq!m*z)fk!88_X7@530KJ12 zCfZRB9JQb%G`}ez5{!4YAUnMZn^A?$|6djK!dv%K+X={ArytIrFO{T$b2Tibugpp-d|Fb@;Xv3MNv^`TfuYy_qS^qTl&WKjHcC{ z)X#0d`1#M@11$FF8F4Q9`VG>#=5d1w-EYJ1IQqkSfPRuW2Picle8mAkI|KLtPJOvB z!v>^CK<+}~<$!!FK!w7GApj04Tw=JTp`@?OGLU1x*=!%UVm1ENPS2DKPa`YZIY<*= z7Ttt%_r=!+L$GZq$Jb}1px}uOBi-sVB zDP9ab1@?{YxHVH4aWnO;FsksEZMI#Zw*esLwF0$_3(@3s9fmJ~U95sXrp9(5aB>^w zuvIA5kW&VW(0SAz56Ld%dD~>*c)}1quGDPf*py&+fOzeNc}a8-0OVU_6b?rg5?ams zXodqLC?l&cIV>q&qk|9B`IJD6zSIfzFw9oO&3tPvx3?1iVw$kB6JRzg7wkF=C1Ua& z)mqs~QjR$oeZJeaf3Z{U(Lr8I)un{+;27AaVU$=%7OX}~8~rGR3xzHN7u(@4xn^$o zQo3OtwfYFyH8DRrE(xqIDN2kXM4FVsro(6&CTY?;B^&S!zZ>HR23BMnn@mzS|wfpqB1&`tNYcAV{wZfca$vVqJFzO9(pU^MBN=B#E+hjzOJfMe1+P9TBd}kBuFew zZIJDV>+`h;4_W_k4+rLFC2uRV$Y3TPCsg4qn`A&D0ycYFU1_AISgWk8dl-5o@*ENg zu&8g-_ank@Ed`-P;llxrmX#tK${F~`5U%Q&j;kUUT6kNzxPHZl-NXXs$q8u@e9kN!NO4ENJ%+r-0`5MP(uW7-z;hwu|B=x?l%}^I zOGhAT{=HO|JAsr0%#r<220`0tRM@y3{1OJ@b{oX;UOy|PFws9(!iMf97x+f(Zs=W* z_#DxNF04YJXN2&5IG{2>f?hF8}~i8u~?z1|WjB8Ekpxc=uAqja2Pu5&OF zK|RTpYkDUQ=fMOf$b*xWqn-MErdCv?KcgGqmBh{uEQ(2EVXxKXA=TCgu@PcG_3m+d zp$30xoOa~x;>GaY9&&2DC~dt0OO+9dKvp%qgH#ehXLvvNdGPA+-3~+WitycqIgL{+ zmCHV--nF@Qm0yG&R=tn;)eQJXH}pW8&NdJV0sbtjZ6AfU_1^dE(dXv3xm+|C7^+*s zA8ySJlq~*Y)17eZYq0k%ZX9^)T83@%{zx-wt)tV`@dZ7CC7rD8aOTC(L!a^{7^RyPxue&C7#YiMtBP zK;5N$i*e86#>SeGYERG)3&nL|rtG%RmEmXFP>QJ`2X34+G^+2HRTzQ<{@VQ9`QNY8 z@)sBk$c;?k7y;)SI)MaPOf{c#!hQ^Eg4=g!>s1-kxObb5L{DB7^LFXMARQC^`D~Wx zy)&QCm5jE!jC&=N&}MQHZI>{&X=dDo+5Q7t?yd%Fc-+#McOWyTF0ccNH-)tdLJHH| z^E2=*8%-_Hu{PY5-dG7=g!D$J&@^sWs*asAhqXqW3x%hg4!vFr>|J$~{=|1^4SJAR z%_guBJfrmG&7|e~e)tf_32k}{cBtr|^8>wO*?7Q4>tc!qJW55@YbdfhQy`h3o}>m) zHaRGkRd|n^f(2MYmDE>n_x9kc>gg4cQ4vu;f}RgIc`&|h4P^(|9{ys}he#f6E0y_U3I2So43(UOKk$IRC~xmW=-9F z)em@!q7sjxx!xw>r6HnAhiyB)jVhGfKV%?r{A+Z*!eiUfj0=vH?79G1AJZ>5KoE(W zKBf2~wD()~QN?is#R@6oo?&TN2|cQFdg3Lt$CW18HH;@DVLn79NT6ZTK7$dR>yC!5 z*=GRg4p&Wi0c=fI0y-5#!C-UiGJkT^P`-X=4^uP)6M#fd~Oj@c_*=>Z#Xw9l^OJctV6uix%oItOj{p zoK>BR$hO(8^VFI784i);l^@JUp9Xa9z!eD~r#*B~h~CR&9*j^AgSFCq6Nua@W=K8* z9&ijv2^Ui61iCrg&Zfhkg;NqqUGS`pA6A=PMs=pYttDtjc=7%@h^kDPY6RVEevPh@xpHv8w)c7J)8MtXy{?HD!3|}eA)g8)psS25)IhHe zHtlDEYm}52dx9# z#HkA?_YLz9KV}GCg9VM%?8iE%vmyTB;0`BhZM*+QT~{vrPH|DJc8K$~{oQm>2k~97 zsXp*3XVQf}q-n;iaAA&Z*KtbTOkMj2P97o$oTr%sA|g5BXG``@l&HP>P9krGcwze< z-PkBXn(%JJ7J#ye;Od(K$YUMIBXn~K_H}DLV@ErRTbefPIQqEXXv}NOETh zi!qJYGedL@&&fhlqg8D3!0MW#HW`x^^ed1L8$6h9Sw(Ay_EyRs_!8iMaYbhPfeinr znYd)|r6^B_=KH#^q;wA+mDyiH+f%vv2@IfK834$JVjMkGmA-R+dP6CnK9=GQZ3qn* zq~SVwZRV`Ho0T2*NuMI^0TYTGQGzFSq#HijX7E$+UgjMLBb@R>N8{&%SO_N5l0|rE z%(x}|$h?bt=C=0`UxFQM9%+E%?w3M$h~?kCtXRLj2wT{pmZb01u(B(ZNo}?i|9( zLyyy%8Djoriw^C34v_|#HT#5_fs4^sfGO-^K%w>~Kw-xeK%tyK8Gf8an(mdsWO#=!u2xE-uET*aPQ!XY#0?S{AOA$NbpYfcZi3nh9}PMd|N zTtqQq1!vdqqO^%A2j<-NI;M2<|3FLi&@%){M4OcQo(x1*EoEg2I3sQOLW9nBIcV`j zF(%ljZ0eInYJNm5{+jS@m%A0vBlZnw(K(5X`>VMO>?z|DQ~v>=?r54$4n7po8xg7LX&4>v@6u#{?d6y4;0 z5!J@Gp;=^ij#!MoLsG9ihCCNDgb@tQ<2(9AeUEKBwR{=+fTAF&dvWs&bvzQz{2aeb zBifsYmXbGX?yd$<`T}iFH3_K$E}|&Ub`S>#mVOc^oh=6aijl6L zmH86#X6+(=nWS~X7yv}t#0!)Mx!I%se5k}A%{BIgX#5516||&;K@{JjYJllO-E{aB zwj`E8Anvr@mNGxdb_@NGEOnWYIFl4~w*ldw1x^!)m`g_S2v5@QMWEEnA)$#B=g-*= zPBE%?vrWAnU#pHv5zAVdV^dwB5P+qfLwU|ibKkbbeV?(9{;Gktp{F$D8@-r&`!%9{ z{cor7+~o@XB^JBp zQMu+2#)m4dR?J5g9%#x;(5=geECjt^U(|bP-$9(z3D1fueS^fL+U&;`$(yjo`|z&J z9P|8z5tdk$0N!5Ziaf)8qi{|TV}Z`yjOx=tN!400mRhy;z7iCSHl*0Mnw`Q=F$y#7JsKrwX&-fB=Ay&D!km?J;GdL5vRUA||m@6lmli#PdUZYwguKwtsCDBei z;UJ$Hm>_#yRWS^RHqo5WLm#G)CMB4~*+dXmUQP^cEoo-a5UUA$mu+ve-WPW6iv|2I z^9l^T#UXaT)!5-~Gxf=udp88=W*tX zt~W(iLZu5F^~8}eumVq#9Z5cd6vB0k*`y<=rwCKls;aE)kE!Vk^D9Lz$xDdfH5n;&O&?lf-LmNJ3=1V7A^ zN;BY=nB(2rg;89E3Y8zzWWv|czrtL>KKRZL6~O%w8SIK)~cLXN%;g=&)h4OKccy(Kdg-?twRx?Kaz}{P>tNe!YB1ey%yJih zUce$52ct}3+5n|y+rQKaLcR*7l`?seLyG$KUeg;_hjtD{C!EyP-vyR|8u%iZE#2&dB)(O73i=9+@~661_1ks zgaC<&uoquDc>j(`NOeNg?-raPN@D zpLW_T8R#Bw_L&)Np8TMAq>v4d!1JkdC*0uw6Jne_CLf{9Tp3q(sYBUM)nW@Q^%(eX zR**N9lQh*K*xitk-!gk-%UqZL2qEXpM18A3X553|rc0ousX%U=3uQPxFNB7CGo1WC zWmh4+D0RM}$_)3fzy){QHR1gZ<{+(DSusz8fq4O3r#%hWhAHf|SnO2FmTOBs!T^Wx z-9U|JAmn8B%fP;Srg~61&zsnE{%`T#&wet4_r^jtgU87+m>Fkg0Umqg-^YK^kCdF2 z%f?JDDPpGYYs=!jZQFl@OX50dZo~OfR7@$OgNw*OzL!7?tb9yaV^-E!GMMgId6Dk9 z39vT=Er$;5j+M`6PPM!;R$fe36VPys4Y9}b418zRe+qN>r?e11TH2-q!cVqk0O7y_ zp_>Q`-ZqAh--HV1_Uf@E^Z3l;`VKf9)`D|XSDeK>GvnmD8SF(OAH%6J_wZ6Z*mYa< zK0N|{&e<6gXV|~@(~gPjoO>4P*ZY)N`eCkeR9$hN;w6(RNs0oRG*Lbu0Z0KaT!*1; zAegb`KSa5>B^%yi?HX_wp#1e6+4#`(Sy62uyx9a=Vi7LnSx8u)U@G`2!03Z@1PKgQ zktxq^yPq_ipt>Bs$%(GV+>;`NPRHuZlR}rLS|6>7`PE*f|{iMq*dWJC= zugbl6RevJJ$?MT!`^_bV4)z>ULYnH>uN!nvgNUsHcMHgy1d##H;eS|qkEnsmz+AO# zLG>zTHH&KjQ-7_BBI@_2YHSD7R!V^aEezT-|<6koy|NCLzkhb#Bud>nk9;gzf9%Rm zdJ(g{Q$PGk>Omq3!#ofOuCCOl@Lt2m`aJd*a^{nTRX3;x-!q|haQ1thef7>4au$%i z_0I{PQ>%X6L?$0Oh0>Cy7ZOxn@OCcdMS+|XgIihcTO{aAqb%Mh2bK8kbR4?;dQ zH_i%qA~$x(HCL*|6~gOj2=0gk??4yydCUXvEJCCDUQhJuW@PgV3ACqAgh0aosW;!+ zk2mYBefanAz&i`^dgd-VaK)|EBZsvme>0JrWoQ9Hfel+xY)l9w-{FA6-vTj6sh^~S~SrFG{+799NqJ5Bb$Mr-VT^C@-3SjqPDpQZWa4v#L5e9f} zOF#hsyCNqb$AOh>Bc7koz)}wm|Gk&a4GzF~RUUx29iV7FH%SpZ!}o+2b_WX^BPapg zNueS&;0U2A<+zW73`_s8NVRZa!|Q0Y_BuBJ%gL(MR>&0=lnA4k_XKh%2iz2<-Z(+) zePG6qmPwt+5c%LJ&BouOxlg`kLetRT&}r>wxK`GsP{4apn0Sd?44{53l!xU+OXhr2 zdC8SvrIr+o6ZuJ^2xLlBFX+N&?2@-iWLFA&C_CNDb9)!&+9=)oFi6$ds98TGg3>8c+(Fo9jQ zbUl9$v{#S@sOuk&K(L2ha-m^}B|rK}UP&O-fV-W;1N(ZKqlB((E7DJR9_=G-$!f*? z+j5kmW1JWW+V}uSJr>jlam;rPEvQnXZP%lGRS6B_L%0HGz!8$MXm5lQSH(Y}JJ40{ z<(bNH2u?WD0jeWK_&C@@YT3BdA!DEF5`C&Ubdixvm;n(`Q5W}iK#|;IO=TDw>HK7T zBErC8_;RT7K=epxC{V`B#(|SYLVKg$o6GPO$5W<=#-SeY0-OEp()3YsEOM4j&F|)~ zVmu0ThY4|x$?aL;rFpU$%N2%9PKx5gaMFalzlz+pbcs_3O(cGWPB($T4j^+W7LHy< z-uSlKcCdJ}_Vye-7B5?60fC!YtzC&EFoQ^JejTY~nG7h!cLU{ox^bTfYT!;>fCacr zWZljcy`l^98i>gfml^t>5YWoN5`d8-Y;=1L0g%}QJIuy%mfZsi9xcX4`hBMebs^t? zf+X)Cvi{gO1f@6RZvNPtGl%kiTK-F}Hcga(Yp`__MFf;QOaU+gvq8H%LmB0);ikrJ41zu!!m=}BiDLYHLj>ol*N@aai`@+z6rDZ# zm{IpR8O0=%hiPRaOtxBDrXTkudF>zz*qnQn&>`&gcmUQXbKWyH3tJAU)bwovtwe=e z)t!`tr+TAkb5`(X@hq&bkHTn-p`!q1h(B#>ZFfbM&hCYH(i#EbszfyHp5BWA1$MeJES2pEQt+ys`4UeAj0Vf$ESZUMZQBEF7PhyynByp?e!olXV|*e!)Jve9sYxEjj86Q~YH< z4f*CTv|o{9*hYE5XtfWsw-ELNyh!6qV*Y$XL#}>M8Xb%jyjFC&M?)VWWAv|P?i?$3&bzsDfXxFc)Q~+K6NlX2Aa%pmp_;FYrbvVP zE>YvaOamWe3?)chDQ*$x$`!1OAiAA&R(Lx(4=e$W?k6Y_-X{^OH(7`)U@>gMd$ZiF zmbSE!uJHUXK&*XB0%YL4YO0&#J6|!q*}-X2p1i-ihgc4dIN-k6 z_-?vy$2}f~?6}0cjWe?^(Kn++^FcqrwR%sn6N&yL&Qy!KAMdZp(_N-_E03TrV6U zwf~H83h1tn=_t0_s?6UXl`>o2TBU66q?1!B3?B5pYbOgSrEK_GRF)z;#WK}p>u<)1 z7ne+N@p?X+EIdmxE>R&!!Fgh(S!^&1zeT;5wlG-rFuLK$S5;?)XvZaXQWGUFCIQi0 zixlW>9wWVtTCtpjKm~eRk(YH;v;C&R3`*mga8>KTca!TC{%VElE!cOf;jfmLd0+Qf zJAF&+KIW3yycw&wnbkTKeiQ$!HW=yWRs-L$!F=tcU)z{rqH)Xh#&KLLD5GA|Wotej zdo50PQ_38Kq+Da$jY})u%sQhvZ1-sf9{B-%a@j*~-$QsSav) zPdKREfk$)R;GtHZ84t_!=`f#e*@>{>b_@oq`NOfzhzk zOg5-VXScky6W(rX+1+h=A)d)wh0SDZxpHf>E^s2<@qL5+3H$}|r{eF&_*?!1gWdi^ zgZ=Ng&d2rj_;ca!CUlCSprF8rKNJ3>0{YKfp#PUsP>@T%c^3S`|INr3>0ctBui)?N z_`3q%ci{Iq{LRJnNANdzz>J0ov~<>tcRC z*+6n0sE)ZT0PYmeD9gKzcmr9EhgRdU=#yf+IwJahZoQkF!lOF31Uqv>s1y8gb0_8B z3bwHTTRc4kcXCd6u|YP3y1-B&;|k>A9&bbxl4sQw<8Z5ZhahByubV2_g>^W+hBvv7 zgdpD7SGW#ma2!ey-1y@RAb}zlgro!Ep1z2gDFLN|L-3c1G=w>IE2wgVw~Ib|f}pzC8wBL+;(D^Ey!vo{O3`saL6KLs+-ppt5j001gv1NlJJE z{!cpYK|RoFw-;<5p;b_wP!0nu$eXZTKCl>APyDYP#lXM9*3;?Vz(#Su(S$%PoC)yFi(Dn;K6{k?G(OYj@efNsWt17?6s22 zo0{P7)>9_c>4qlKiJnUb}5B0di z-Vykq;rxv+`qP`%)63Pj+t%}o+TxWY&@Kn#+Z-AhM-~wGnt=D^Yp69+V&#I{A`g9H z@~DXvFwy`u_of1TZJxMxMZm$?z6Z9}o6_G*UYT)kMSeCWwZ&m*ir&`enM+wiBJTH| zexd&H0pH`=#ZxAO{uQj82OfG0s$H?35g)MpOA&xmnsN>lyIAvu;Qis$TSAuRPSVvR z^TgS3YIZ1>Z;?se7uo-UmR@f2>y*|OD4%{$`Dgu+gb$3wu~5D%f(j{KE%|xdK?=Me z&dbBV$#oOL}1yJ{8BUOzCL+Px3)iO~22<-uGD3JTCBeGbDXK2LAj zfDZ|4O6NRuat5$$(xfv#&e`Ar+Vli!@7ER}H>@oY?8>f{TG&^$vl?kwp};B?%O4qN zzDR9va-#kd>r9HGHg>H`<3=Q1YB4`+qh}};C_{Rz{2lpF3$pc(Xy3*cC=SaHz&rmRTxtr37rsHsv$Z$hUOv^I@&z=SlcpzDKOd@S!h>})iLW)Z+>-zal#HYP27=0L(ae%XGT>K}KQNIL7fgdbmu-YTLn2 ztv1Q0;x9`z5lHXxR}ee~BaXrI18iCNR~|1GA^MxH!R}Z$8MA(obk-ejOk!TK^e~`H z4;fXe4f4Z;@E}35N%4_=b|4780RF5YK;_g?#4GLhuhJ0DnK<^;FFN8W6fQS#z&fl# zKTfNC?|B+DL{FOwx)Pd!+`tQQQ|zuZ;HKoD8q%PxzKXK9a&E~ywibLW!zn3i&G3B%;5uSOn$?p)M6BGWB*1GAk6B^G3oT2~S{%oDOSjd8> zD^RnW&>mF(Oc`5`2l)_JQo?)-{=6!Q@7OpKiuHSFP|!gE-~?=b6!jsP3vN>}e-D*g z4EUBC#<5-Rzz1}|*ac80R`t#yx@@3ckB%lXejU)Q5E^K92NNxolW46}fzdw$AS<>@ z+kr~tGb|kz@PyqXQl!hgC|`tc^N8($W#S2wd9->&^7dc?BCPBKOsf)Tm+io=a~g7! zpld!#HHc_e!3b*}coaE)xK<%+JVFVdT_^u=TCC!NT2f?Tek=rV_AnZ+;NH5y> zTD7zi?M6dB&aFzL9bm`i z)A>!d0}q_xmhQp2O}I`W?G(Iopz!D-_@k(?(usnSuLon8iBeAJ?5-Pw!*b`1gxEc* zHks)V#*l{ji0uWiRMqhT_bCF*LNV+<1-L7~*$OOi4i_2;@mIoJ$CF-4&La(Z@d8r) zmg3(*+X03(i%#h<4POFDu2b?U+izaN6TPbPSv;-p*`rqx5G+jMaLkMvNWRmg7PB$H zh!6C0pqxG`XUT(?!|mgnKP>7Gkt(lCJ}=`yoGx`SteP#XuM3yv8iQuiOo9iU5!TF# z^+D+L@$Qz>0<>@4V-qyB;W^WPIPbf7nmxseli%t08edj|SSFEh z#H@UPx~)S$a>T2Z1Yy&rGf;t2qN9_#dSS4l)3F3pX%4vVs+E`E%BG;9kv~ciUIuK9 z!9eKVWg}SipMa{QMHEEGtn5WUL#avK$V`qA|F*+3sW%1H+(i>qRC+KTsPO2AV)Gcc z(H`(L{a{cKl?rn3CPcfnHvSq7a$&@j3bRsSQ7Wv}N`<`+zQmewkZ6tt@?%IxZrS!n z_Fc)E%&rEzD}pNJw*=yIDk!}2C?CC1GlEK$)M#`}(U5M!?&!UQU1TrWDE1<12CPKj zb+*yoi&w~iCiUPm5tnOHWEn~U%h=8_ip-nJTghY))EW;6-vH$gv&Xy0)*-i}kE1C` zYG>0}g6tiD9DnYtf?J*Pm0x=V@55+{ z_hHo%9qPKs#B%W-&n%ZWua}}}>%}QLVETk~>;)#_dJ)s+(w9MpI7GfdP;VzUl7l~q zRb4QL$I<0B*x>l|7&iVN!e=`!U{2L@l#`%cO34Yilh3bL9rHQ(m30;$gVLpL9S3$3 z+>>tDS$+c&Y3z^~{*nWN^GZ|j2-WG37#5dAJo?wXitx+Eh63cmr)kW93>6Q}&Bpt~ zbgM-+wdDDyPhY$e9m8AF7`EC$_);NahyyE~RyAe~P&qfEId9ibNIemc^`_->$mLq7 z?WI^el~vRaiIF6UM^p%h@+^c_R9$Q&3~(Kyx?cTZ(y@TU1SLU8ft`;qC|bh|avhd> zuqV0Fu6}ooGxQaBwwM~1gFC9^h*QJt)RUU97vO(uEq4N>4Ub70n`jQF5w-GSu8MAV z&FRJ-7)nAoL>7)e_^cfDrcW6NubSNwJ{UqZ(>@LLHCpfUpmOdG+x>ccyb+NnUD$D9 zs|_*Bjf|EB1J|zPEyT4w^dTZ2PF%vzqH9P0<|~*!$LBn_$Q^G=5&2iwotT(ie?6+t zF8a2p@fFu$y6^yA>WY-%V@tgBK9HRzI5>P@>SvEu)=ePkm!sgxzc)-o7^?L|5o#}7! z0dY*+yyIaHlM(bP|H97^5fVoE+_)n^@QC_d1QQ6h63+OT>exbYtIwE`A#wsW-6s$# zrSuVfZnTIcc}(qkGI$cd_U*YSsb}%%DbxrEVRix*-My*knB=+u0;eor_^<*`^k6GR zb5xm6Y*&{r1VP=MiR_k8eB06gqC~_*!;=qlT91GR{5S~bZmwpW!3LR=?ON%;lqKrJ zqI2@qWAv&Bw&Lw_ypH1Ni&*B1?ev8a%|c1;;I_uy0+r>e(zo4|&0b8&7$z96tTcZo zMWiu2lG1zzWJ?zQ0Cu1y3vK~ve;(t9*QvNJFp6>t9j1g@1f-gL@K*&QwA1~fZC5Rb zDMxI4s~&J%qy?IgwKb7#h}3LJ%pIIo{Ks3gJG$RU)0mzuc+=#;syqQEnX&Iq827Qs zi;g;oa@sOv0Y&s>6nY()6|g4~C>o4*<5?>{ticYPS{3;x7yufcle(A~UZ>@$Ww~VA zM&3Pg9F|LUwHX!|?+M05IB>dgR5N+7${D4W(DjFlF9Ujpb%?8RzJi%i;)@X^nfNND zdWR_Tv$m>En0NGWh%8#tw^*>C;kE>BZt{$yvWp-hQ*P1bk;&U7vr-H+8^|P~g%(E0 zTEbsCZA6_xnru7Pu`gf3?Q_`F1I&V>(4}BuNyTt{=RT<5f8-Xb(QPVqC%we{+QicVM86HJaOdv=Kb12B91($LmEG zA+==q{-2P12~e^Xcz}6k^qm$I{c;xS-yEd|guR0%nyd-5q%5EiT|}iZG8hpw#d9-7C;`*tan5ZA4Ih))G#2U2?9~~ z|5cj^*T#g^q*zUyfsOO4Fip!)zcNd`R3I0S`acWMxBzpw-Hu9!V-^enVIJ(@g0ajL zq%pu69O=pvK zVZFzFWaA96{GQ8|NEyYuK|4O{yUDh40z-iNE@bmiFRKEEm7ed?}U z`9-LIZz6|eyZam$*e&;E`O`O)C->o%X_;eU0wCJ$IxDbSA2a$cqfsk4))Cr8Eq&ky zJ`ocXOYu^3#SyjC%f70|(NZq&xZJ1SW$b;u!Kzw6%&eW}-73?d=5l_1S@N zxf-1aCY=sL!kvRm!%hKHlD+8+Xcc~wr|H((gnc-L-)aN|Ve}XwhOu|Hiecz`pr9v( z56!o-W$xpsViZ-3iC)zDWTui*aSI>5e_0f_icZ}nH3eP%d#P33aNom|=;XV}LT+Mj zCIwF^QNr(z{;dzuu+*f`gy}ti=2Mhi9OY3;Z28}>;4i{_q!0XXk09IRH!S5 z&9!2a z1@y;#{;n%UUOA+@O%~fz=0a9^bz?({Q;4>LE_@QcSlE<68>6V0aiv4zc4*})rOX^Fv#?>R%&Py`^&iI!{wdV&oZIk2ZjiR8W+E{YbKp6p zYA&k~dS8>rU+S4aYXKtLBpW_Q>)U@{@l2xXvcF<1vEM3OPEYf zEtg1qlO26P){r$;_t;(U6D!Q37Vve+o zVO-&m$1pp}CuT?dWwd5?M?t&N1ah$PQ)}U`!^=CWw^+36mCsaN#8G*8R;raoH+(u_ zd5+7ym?5XA>Pyq;2detvsa0Rb8gDDAK5ZRNKTn%C7CT|Xs^;8SRYbOujn~LtsAbFM zU#lT&I% znxGxi@ksa_-GUkAjK8iRI;f{;^uht%0R;z^_8^0$?z5c3Ss90urIEq(@3F+_Yw>*i zHTfJ`0}#J)Ly=$cqdz2`%lJe*&j}x$NSOA0H8QYE$HZ!Dc&upSg1W3cU0Dcd5D;ve z&F~xm64$r8Z7k=FWq$wh#g?iVLei*J$1#!g>l4&>k9jf(O zAYbgaOeqg+2(oTy5IrQ$MK4;go}g5i4R;V)R?;zdrCBcv>&SF!r}N6Rr;v+U6W%<> zu<`vEd)rfeL_hF}@E1zm6JO*D)GI&xe%ON(crYKa@DD4Mb5RL)rkgXBzE&}HedY#K ziB=UHyyQe1ElaQ(^_I9MRun<7P)m(4k)#OAcUi;=5OV2G8))(3-q)mycy08#*%uj_ z?z1d|%kg5-F`7`VQLJnci)z>TYc&(HZ2l{vhIboSk#(JYAttONeeTL z|MWG4BGE9Z+%nqdZol&yY`ItQiq5=*g*`hV*P?XGr|juB?tjo<5{EajguS--FcW{I>+jKnO;a8m{kQ8IT%!>y{6B3D zZ=bd~;NNYrGTnW!tVmDf$&c-2B4qir_13)ENrXBR9^GG5U7O_xqpw}pe357OotV_5 zezIT=U~<0`Gj;mh#yT?9Tc%8IRGg>xe7twln#b(T1;+YMfkN0(tGzY_jxp<$y#%)Ai) zn%DZ=;M#Z0%1^A>Ig3`(qPaMV`|8m+c`{hzgKG;CYm`sY8f&8-702UR$s*^bS$L?f zxGwt2b))h4;OtKptu5$Sqbw?7XUo_ko9U?slqJxR{5ppS81W+ ztP)f$hTiq|MPDPsabg7!P6kJTJc_dJttQ z|6i<~3v?7`700tX8`#3iZrfE+qehDgPSt3lf}3grEClG5&@>4?V%1}#)E8D(K(hhd zMqP)&dVJyA<6Dm&UsZxun+=$RfRGTx(8d}Sbudu_#AXv>;_u#>O#-x4k8)1fnQvyk z_jkYh-N*lizx#lB)OSlUm~b)^+i}fu`KIe-AF0zVFvVgNUxRe6_}wp(rEp6SkwtSL z*2$=J$*9b$G_#po7#qw#uVKyoMG4{r1d)$t)X7$N)eX{73lI64qnS05sHcR2ydVBXm0;Sbw3JP8>OueLzA&1e5QE; zm&khaxNl=I^xhQztIWnC=ee4P_NSSQxUWe1b+hSLuCJ&zNPC=C%`EAbBNURISH&)lY0^A_ zf1({K%~U}dpO~o{u$Eh!19n-A!9DJ(k+$@@_%O$}91(mNYwMs0IlG059`)WBci(_1 zn{;22H^!~w6vftZ*6NmG0u*Cybuv|hTGCl6vm<1lur|ZE1+k~79_Bsj#sTf+nJP~H z*JrAR73NJT2ww%QQ~VtQ}C zD}dlk6%(xNqCAdt5c|rrh*-tY2{)W|W!AWQZVp>z^R$6h)KJac2oe{+bTNj6uh3@E z1Y}(flYtYf9E8VEfKQ^yLkdqPh?nh%q!>rIJfXsG+8$bO$v3r=oECXOb<(3^I&ns% zBxSD^8!gn_J}q2JcBEtqmBJH)QdZPwb-PudSW3`}oT4Jsfs)D1?4=S`!nwNq=z2{) zVVto;uLb5y60yXvD}wkTFRRVr25>2Coi>j4PJmfQnq9QQ92bkD1dHUDFEMIW<;-r0 zVTC=z&3<%iR@G$hgjfJ{>HTrv=1FRY&`5{=-rwltz$jwN__IGUJ)LhD18z>tJl=9% zpCwNDSPC~AIjV170P4*+PM(s&!r*Fh*)}7`Q2LtY;a5E1vr@z1mQBhX2Mt7vZ(HmW z&jPSKTb_Hxe5rQl%UVN~k8BQNSKi|KumzbHtUbG;*xEX5u>uAW^Hw`XbxuT(RU_sZ zqY9C66tSvZ^m1z}KxxL-v)H6SRjPz`nCw-|?x$Is&zhS@kyf#ANjAF4#UvM5VlOi% zSY$fgcZ^C+bxoDB_LFI^qD)M67dKq|8-TC?`Ld?bOIQYLoT zFS`DyD=@7^YNfDeqWQ1A7m>alRUZ(E8IWZeAP2`|Qc9>DW+iy?p4(m)$ZK#=ar)KF zahO?Ug_c`cO&?L8Nq07i2?j_9GKtz`qIZc&JxLk@U#tbfma9-<@&qc~S*SKqq+*}1 z)CwPaDzefL<5(%~wnfyy3N6Z4Vy({jxHDV4!^c{KE()e@bIW$}W#*mMJln$Zu#E$z+0aISKmoMxSw@#(^SQ|EmZh1>8Dp@t8HQwS0EGk6jMXc6 zu~od%;`jPQoH<~`zvp|RZ#$L(%*w--*#8V@_zaT~z_IX~atWuk>!&aqLdWAkFvILt$%FYWl4jKB?rTi(jUxeT%DLqF>VzA6x9g|)dX z)9~5wzOQ2v=+0@`zw7gme5l#(h_L&-8_Uz|9ZsPgxPZU(vP5KA!cjBkYb9=ik^_mV zJq<5p^ebj0Cf^R1@x!b{tKqYvI9;k`gse-jLk+EXk!4(js!#=%^Ah}=4sG}blrCd$ z({!za#2bGgW4j?TniRa`i<#tCy!Eg?U~RiTVEL`+^_j%CUCKW)OObO(=XER41c+mf zk!G4az{sMqghU%h*nwOy6s5*Wry=%9D5Fc9g(9bPe?W(Y98R_b7N_xR+)+?YkPX)D z;rloE`JNp~>{q(1y9C$#x;fQYcvUs9q<$!T;DXlVv~k2OJuwRT*OH~!gu4q((kA_; zTP)tR!2667mRwHB)Skv9WuqJo4^zI>gc7f)!SGczpmd6wsX%@=vUn9DU>wQUfFg7G zS`6sZZmmJ9)F5|d4f@%`|C<`*i>E4*&-kO&KzGAoxyu)8C3$d>k{Kcj$I%*9dKsh} z)JBHIs2wn~qQy&{rK6THE);o8R`I=JFW7Cy2Si7O4l)R@i5gS z*bSbNSQezdEt#F)lK9?xKEdbbw;bJZQIta?=6SCoRP$^;%O0+woL(j$f3t)aImw6Y z_7CcaY&l9fVh!rvC3++`gDeKvRYQxd6KtwCFNVVPleDE_QY(L4I`)ZMYCk4Tg@xUc zxJR11C6$xMI@oUiX$!gdpgcBej~Neasoi^dAK&f1W7K{d&XWO5j%uT&R?uC>Wy=Mr zJHyU5*i{CFDWUnhr4`x_Qe%_eXJpu~wZo*9l7klGwo6{;LW487ZG=I5)BTVzw zmh=G{BD%fJnP_?zO^VMluL4t|ukS7mO?24YWd`T$5u_U#dI`x)@5JUsk)+R*_dA8Oa2kNrB5zm8~LCxf_NOv$4dObA|kf? z^t;suBI&j%fZ4ad0q40T4-`biiw2a_e&;zC)Ovboo%qnyRBxhtIXG6!qrLw?`Stv( z(^p?4{Rvm6-M$uQuYm3zj)8L&lE&X^Y?T9{>I-`_Hj4P9WUG# zMLof2iH0I%zZYwCuZJG7f9Bg8z5dyCRsVeSivDT(A^mf|*FQg;+dr!xoYOz^&(GQ&6Ib+4^y^;#9Aj)A=I`3?@EG=YQbX%)OHJJ+D>k*M1F)Tq9`{*0jd-_fiVJl(UV2=>uNDo3D#lLV zFk+k*Y)MgicE+P&#iA5lXKkqAT-V>Gr|0x9E+Rp#DeBll`Bmtdo-OTn`K4Q-hI_KL zh#?ijsy+Y4^ZxKuEPv-DnC*q4#lLBa|A2s&p9)vsnh1(o$yb2u2~M-`z6NoeALD$h zYb+~YY+C|-;TcU5?}K2&xi?LVkp}Uprd1k)H4C2ANOJ<>I_jEmWF^C-8+=m+;&S;R zGV>bF1NMe1K+%pWC>q~u`wkxhUs7-hcI+r9&?tY$Eoq`8$xB9u2V7u2)}vdnEq-nK zQlvR(Zy4#zF)a>8+_DDq`sQHaOqna5jG#)o?+0bteVSw8YZSIa+}S%^Z#bo)Z1HN& zmXNO%#;u^l?R)8RuLAsZs9hc+tGW1a+E?iB7=b_Vl-R9h7)N+O9@IeZ#nd(bUI+P* zp^NWq2R^{^buC`!s|Lume;wSVF!j3|4sjH^TK}iy@+Yo={t1k{#_6WAm3@DTjcpGY z?dDYPU&JJS*p+d*^OG%z0Fo!gIJ?d&L5&QYfOzcQV6U3$bt>#4!C&T~HQhU9hu+D5 z(YrWQCeMqd(Val^&7fu0W$@u*s_^LFOPQ#NVkrWIN)&S^H%H>bQ;$^e7*~n%D;6JF{6oT|ihYpK{=&Kmqb#~GAOapzmQAHuej1;ZD2Ych4 z0qux|xSm(*%-T=E9&}#w}lJq{Bw34Mpj<1wqIu_H$g+I&o$aRr}jQLE+ygM9LXlNp|!QInbL_ zD<|Rb8yxDyypgHMbz(9Gu+`o+#Ey)L24jrk?WBhDA#}S|yB)GH>CedYrLScSzT(E~ zv97VQ*7aI(oNnAE73umuucBSt7Z+PcsS=g!RzoN*#D-cYkluCb#5yF6(wP(y>)8O0 zFt^g~)rSvR7kD*$Nq2+|7{D?&7ekDwFjy^~Of0DO)pQBwfXGpApPoG)JgR+au=I#> zSVhdc*R;|ft=793tXBta$pHOWlEIZ~Gvq+x$}X|jDmf@GV0rTe?Z1j1e=LpCc7@c;}M<70S zIrJlHCGN{GpAtBZRNM7a;*M53Dn7mKhB!La=2}i7aR~3bs7r8I;1Nd5tW0)w3Rj8R zsF0BBtfD8Wq;SNeBJ{Bgp3ndhj!IB>x|_o{YXRY!M>MOm60Cw71ZofMyMP0`fkh$H7 zFy-==b0krLOpm)WLI7wtMB6wi5*&m+Gz`i(-)*bc%Hd314(LF!YL7<)DySaB7CUGy zw&Fx<-EZODGi&}ehP?RIpPOCXWv{}vjF z_lVntS!yrEX=k6xPDc!+T5gB+P4Cx@@wjp!Dv)9lPjD`mLwT!JSt93h0^4ND4`psU z#AL%4b-=%p{-F=(pxEi~Ua=Rc+2m~CY^Y8GK`YgU2ZHSHMx0YTt=66T7(1OTF-$9a zW;GLmjjVd)EFy=m%8M6rx-Iu06V}#?H1F_S-N5jSVj#|BN)6}9qeae%!@SKG{kk6) z3jw@D3;052c0(5nfeH#y%w>F@ql_;eAv>ud>%-3;UFlX=cI9<6Z?1LlyZ5`NQ|in? zw$-T_QA?P)uhe+2Tzy`>|Ckksxbb&hifP2tRx||B1Jw~Zxvp4k6JqV#o>d9PMbjTy z{(Gi-cpdv`bv&QfSum}1yR?n-!%Uh23|Sp=?0hVLRMn>jHOzLu>w9oY_}xb9UJd=$q8f3fL0#z3x`=DL5t88G(cO44t)- zU5B4<>2CzPhg@022S4Es0t-0K(31(KIGdL@s7KN#*qy}M(_BlO->){N@I`( z9tm)__mX!c*f1^S=+VTNKV_;Bebd6*^^^x!U)pw={ep`{1XO_FwU)8rb09O@m(@mu zU&KN`q5y&`MJgfix|F**qBm#~)hg^kiL6~Bjw{P=f5iE>H2kx8F~z__P-)(#SHz=^ z0b@GIY-WzQKa+DNhdZh3RUVbu5x{)^N%yG1Ipm@mg(UCK4L zx&4hnfrpr!;57#})aBZsK!Cm6rCdah!ZJJVNO2848qf^l1L5ypaQC1YGDcN_Kz|M& z;s(T9y1l6Sbe`%A&uW_BPG_DrbY1>_M0%b@vza%P7rZ}WiB;%Hq1Vzu6B5_Om;f<7 z<;wNa@rZvF{l#{uC?da|Ri!^7UKQEtxeqQ-ZLY+*{Fr6n-wy$S@(U)P75Jcw?e0Rm zv*Z-rou^|D#ZK=kv`%vg%Z&3#@}<_Q08{Nj#fE>91!4P;i-w~}3Hsr%#fJ~ZE{bzD zpJT@_-%ij1@6g%~EG_Z&!=F90!LEAvhBK0{ZDq|y@`vrtY2DiCPbT`&V?&8qaJK=Uu}41m^DZO2Ed zo#+2T1-0tdUwTC7-NB zAg7Cd5UkylQ58S!2Mr^i^01~T?zr@tx3&b{NcFnnmncz^CARG+m0-5H8Y=uvh@O&3 z+{;BKK_cAGG4gfeoxTgzp;q;f`b!-aw(dS&FhrRkH*Ip&BUkszRhL|Sk1N60=SR!5 zv~WvnVQF<_Bk7-UG-5)$YmJp<`0N=0^hfVeqJK3#yX~^|q0Yh9L)lAyEoU)t!36F> zP~DW4-6ubA&(7<}&tU(VlmkzyA4?D7zdGwlg{>8i^04@6-r+beB?*Ss2?yZW`1uJ9HgY(@4NlAMu4nj7L{T z;Z{6gE1~V~4qOC5cC69#?>&wMI_MwR{DK!eI1G zCs9@R*ojt%h(uX+>Ycs0X?*n{BrfG*86}++4Tr<~3Uy~}#dJl`cU%^Z{>Ra%Gw=mo zRds>C`6(K4pR=8U<7is=!;1LAo)O1xwKpf6f&ktm@5Sx_*5g^cJmgZ8V% zA8?0w8tZ}$LiH}-5xB!o(iC{Yr1nkt0D(!hHJxA~6S6;(>?a(n0LdEUMBh9?(Yaz^ zNv$CV0mH`9vv116jH2BbNl#6u)Ra{brh5PpT9I^i71CC5fpR#l${tq%rn<%=6(8dm zov?S&v`Wx8Bvb$aQzvoUd&jG582+w$XVaK)j;-{a5U8EB853Koa+gr@ZLO15v=sqJ zK+kFeR=e5Z!ugkBQ%!*qjks+Fu+HeB2RkGPx9(X(C1#&_krNf`rS#;?H-u`q{G-_U z@aNmtYsAjPw+VM`wsSVQ0&oL$~*2@v`>tgI&WEBcPc=Vp6fDD~Q^Q0XrOZ7HB8 zKleKCw*(@8z>XiLOWUf^9ax<;X12P%-ucWwRGO*XU?l{g!a9=)uBaVsTE|G(+mQ^f z1*IdeuT;~L5cpPq>^^vwPWWcZY!tty}PKPa1x7*Lvq514?<)Q z4P9#megu=k#Mb~oYvlc52;~uVh+UC5)m&~z3#>7TBz{4}hionYRst@<8mOvt-HzK0 zvAvTETwn#i2H1>KO}}D_LtX5Uc$c#b1P+9v-e&|p-J28GIBK@Zu`X&uv;i`y;@|Mr zrEeFw#I?mk#Vo;HPg32G9UzvblL|E=NY&`wJvx=*U*Rad<%G;K<{$NEn--XW;hP$t zT~Gk6mY<?W6&R8Z$h+ANb)U1MQLA3DpgYZWTH-|jUd9W*Hai>5vDt6n z#^$`Q*jAr!t3r^2FhUTcL3m~oL**i>Q22Hxh-0Te6KNEnoc*)$uReHr{HsmMW7L;U z>;6!Srkm9*Ti(wVUsodCh>*BLR)1g*s$n)?v{pm!2>+}Lv!A?LEH|qb8&sXFYQ?Sy z{M0@t@Kbv}@Dseo#REY-9coXKP#tJ zd&K>h;j>5(7_0V1VZ+MnJLAU`OLqw|BQ(l;#7u;!IQUm9<~0|tNR;im#*-co&G*bE zta(LROwe4ip8E(dHWPa@f`*Vi6Y_tilng=d=q= zan>4-b%pJN(%o6vBAfZbj2B_kti-jScX{CWMOq%JoNKRfpl-_E#U`_H62E%-*J#X6 z7>#DPhMYN~rsUxRx4jU<@LMM3k-lQ~Dhqv9-sq)xk+uH_$uyHYmWrmH?Z(tFB=~fr z6{>`3TubaO@7pd_+_xEms)^mGA(CSH0OKX>zgGGrT2YU$Vc6H;V22c|y)nG^iDLUW zwTPEo&?&`jl?$tOsW46za!OlSWW6eC_HPj3{3>HbycieYz8e}UxMC|}$;!Q%y`cfg z@&Ly<$Zeubc=q{9Ms{73{T(9UEJt7o^|5WfWE|4it@h8}tl7BmndVGBa z4D>B+w-vsMx$MT0EY^sVivjn9$qG9A)kV1+@|;c$6l{~zv9&6wb*R=ii=3~1jC#zb zQHLeYM@WYshLyXvU`RjG5{#gR}OC@>%?iQ_>_!2?X~H`ERYWm6RC@7a5-LmA|SvCMfX)OaT1SH)A*B8GV%58;RISqoD zyxkcSL(Q>OuNNN`TIzQvcWy%hT&XMuE^Aw*$0q*H_>sZ($>FzwggY1GjZ&O13A z%UcRZOMIn+rPs?&16D8~nen|896sPxAQ`eAis5WzztazCRK-a-KO?G}EK!i=b;1;O zxW+}`z5S$MfL`iCbtr|Stq?M;ZSOP=agaYyM#5sDn?8 z<>byMgE*Xe{C*Q5*8&3ul+EJ{?dxyo;ZqimbwMOe=%RkMvB=yQtu(SgaS|OO_q5bA z)49c|#}S6D*)?_Dtlc%0zWhd@1a zFGZUQ4@Q+hEFogXdLLUvHSXB!X%!q}F*vDx52)qT&>cc9Un*zF1yai6C}pTHUpO+1 zz;!Jr@AQX1m0kDd-3(1>*QR=BZHN2qGPt6qr%E;M^eG;6JH0p7Pwp*;R1hL0zgU)q zitUQi*$OMQ9HPY@mK~q33j6#Rv3ISs1*W9f4jtr_2D|^K1zsRI#omq%rQtc z)*>15O+ddz_>x{84BO3ItccD_?o_sds@|hJb;q4PI>0Jl+c@^?#_Zq2h(lSeOPyWq zYM!Uz^Kc1XK)Q9!^9uY@PPDQw2cymR(}^WyK?c6iT5ide+cn%TV>?gY*z{SZ8x`i@ z%=WZO-L~B3zD`ePp_Q~jLLuxeyIMW1{E#?Y>T2v(fk07By&e4?#z4v+Eyzc1hI#wzS>qhP|qRFgkZ< z6-$(+XaBHZ&mnE|0`&ELm-YjuujE=0Y(u21C21L)Ps3y^wIsZEI}KZ- zh$`9+ji-A1t6w|g&xCKr5^CuQDLlah#|-r4d4f%!wH%qHT0k>@$fa2C6N2Trq!wBA zf$Z-MtPHffo=VTmC?7{V;~|-mH3Cz&B>c0rMdsRQh0!ic)+8p*)a;U-ylTnTJ9nRU z7t{(_u1~$wuZywX`PqHK)X6S8=<6LH>o3g?Jy8~A_)cHFGx$^G-pBei>Z?Xcj^;0JJ#PP#oS{C81&<`#^vd)rf~gHFqAyRb!6?-yd)!NC zxsZm#UX%Aj8+6^EI9OvG75maK>!;D@CnE~0f^HE;22z6tA-4)0APc1F%kJWs)Wxy= z>cugu&k6B*s$O+^cKQDFD+-!lQTnjT+ooSCTk+R^a(R7p@>8cd)#=M=1*uXjS=`i> zufq>L4bP+7i!4Qi*v7Q4!5TSJd*3?GaQucYjVYK%#(@di98}rEQx8UX}d;PcIXQM!m((>n6&8^jTh@VK!Ns7Z%JatN#tNB>G*-R8Y2PD8`|IjDp9 zDbG&L%e<5~_#APW_fn4pg7PH`&EzN#Yjdk0n(G-1N|*82O{Q9Db|ujkty{WIe1B3A zBa5W&LDo5Ry)zaMiArkUk35j76L$1N)-h9n>xPlH=|v9|M=y?9uHhPX9ThhkVyD0@ zAXyu&Dk{HvC-n;LG_&IT_v27l%~2{?XXP|G=hxueWE#5G=$gg3<@9g(V}WZ^Pax1G z&&%-%W2GQ$EVs)#;JFgVRPDiMB>OECjj>c{*9WLHT}RW1ue8t>Nbel28wyki&~Fx_ z4Bg5jaNmR_TMEd&Mn6<0vlMCh}vahTquSEqzVM)?pu`3r_x8BGg z?vPI3A%pnj@Q;gN+sNV!+GA~ELwVmH=xzl4vC5^SGzBd(jFt>NQFM9+vo*ThwaKV0 z@B2LlM+mwBpD}bZarY7g;G`%IMvCxY5+{`dSF>Rhl~{oiqlX?eGO7D4ENl8?-V~Ln z{0jpa>C3h7G=Udl>Jv*rwJO~mlP;J}vO~j*6Qg7Gbh2VPSw5XyKAkL^PI9>Ef(F5x zD}&z(>xG-+$d)8-@>W_ZM7cA68-|s*y-|wv0cm&{N9f z{qy)OMHn-T`z?nP=on0xPM_OY45cTv`$Je{84r{`+>X@U738sXQhhF z6dFxVD8+g)2>MhZaLP zAs9NV$`-kSPf>{&Jz~#vP&;iY&e5^nW@z9jl^zOOIH?U&J>H=D;g(u=c9lLTzL^a< z-r-QcZ;xvI7cWZ|+0lJibehK%{c#Du;_kNEJnm|?%@O5C;zcYSOU(NcF!ue~@p;CA zSje9uOxvbCd}9V_no)%*c#0nUDtI`++;w)Wtf#4k|@~ zEMNi6-1mN;atOG3T4Kd7M;+v|le9oFC6{O7%a#7KlsWyGmvk)$-Wk5XXn{4tA}|HS zs1xi3QFuU)gfC+D0lf5(*)J3&zS{V$CBE~mcAynags5>4Z>dbEAEB(#Ay!nyLQn#& zu4;td+Pg`@9}sxS8g*uRJMWz)naLeXIcBuAnbh7=Ym$r zkRkWA%fU7@WdT0UOaZU+N!?g#mov7;1N110=R)JRTyQ>?L7{sw0Ags;ZyO9$-O!03 zehqy&pt9j8s_WWQ=e`TmK&7-6H+Yp=#Jn;%6DEL!rpXjd@3W?F(Oy7uT4qJCSwO3u ziO6{|WY&f%s&6F=<&StS>@{Z@dB_ua@b!B=<}+yY@Iodsw2+_DldgdTVjBdd*Rb;% zaR}qmyx_4VUeSCbrP6QPgyv4aQ1W{3kKKAcMQ(2Sfz0r7GS2vhuHmZF=WWp(ip)NR z8DFZ~TWG7hyD8w+d8<#rIO5S|iKW2i+As49eOhg?K4-SWYN4dnrubI-i0Dm|&(Z{X z+iF;P)l0E6DFVte$ILUn&^_|<0A(+WFX@a|DDPW_bic}suT~4qo8=-IrKwt;9ePS8 zv0O8}%_kZ9m_f2{T8oTCg_s^>HEuzKwn;SNRJ9o>Rg(O9A<6jcFA|R9DY0KSKamZI zKtai{l`Io6<-AlO2quadhTAE`eaw&zU$j*f*u+I6Mr{v5h_`e+-kJcn8%fnEe=_9R zt+E>$IgQ@5Tn>wY74hY%LUx6rMRwrb5Jd0ZFedE4_W|kdMCe_5a@`GzfD*MRh&?6y zH$!5bP;{ai8yi1TyI2=9sySr6h#k0ZikR`460oeA3Kb5A#fav(gyo~4$5A$$PK)EE z1W^VJI}<9g=CfN>Q~t7fL(eulf2sqX8gTa~-ZGCGQ<+7b^Y!QvD3J-lKK4=yYn1}b z`BtBBM-v2UMcM0nqL}8@R+k=uOQJjq&X;9AKxs1IM;S|YtW_CCqah@bBO6AM|4u0e zxC=geV@5E&mA?rAO$4%*x5m)lYQMH{Ubq zBc`wdi`@K#$>b@R29Ghu9_|s(%fUH#^LkVQ&|5@U&d;~{3*^u?iJ6#4!S3|c$-X$I zg2JU-N9yIiJ|Oo+8gfX2DAmue{??@J`k6TB2AWd=d8Qr9M4&i#OYiT-I1c zE#H8cYNR01)__q|FJ7Hz=pYOX7ds#5o}MN_v{3PoyiuceP&w@Jowx8z4Q>`o!1)^W zX?E(o556mM_O)uJrJvV3$Bw8vj9k^4&Frjp4w7WCpB|3NVf%o{+`LHgOwlFQZ&ecx z(`EMD!VQ}d zajkn+OkwM)vi=dwUMkdJ(ddw8ij_PmrhMO{Ce%Zqf4jw;@RidTih~B$5WZiI1|cat z0iiAT+ZAYOx3Z0KazVu5dftcjv}>W=WUXNpZua}FS_+i};_ch}^s!hpQ(9xD$`9YS z^Lv-$yKZtrRPMS)&o!=%ZAf+L{R(^9;E#kBOF;+Vpjyja_nJJ;jACVLh$45 zs|34oa$&a}Wwoe#qxiuD<aU#%VF94j~Mz ztU!X$^auAW{qN$(MC-(y$a&^l#UnzGxF|K8>$#N;b(9j!3ph`J2x6WuoyMvNvuwo5 zxQS*0PvF8Dkx*BKV-KO91bMxbUK&{2>6eUJFWYQ!Gm3yxfd7*vP@kW9v`*d3nL`7W$~9LAs4 zeUdk5k<}wAcJjnZGZb_UX(3fiJfFZ|IJ`m&Ss7;FlPfcdyy6x?K#uRamOV5VB^4H! z;%iEU8m(&@v1C)FTUR5sZIp#H>IEG zKAB`142Xlf!ZJAAD$KpCziDCG**W6hUndUP*bk4ZeB4d#NpB*1GqS9cs{pSTm0LdOl`g zeK}TQ_Y{ufPRC(giE0cj8kep)>n{rxe->d>RcFvAj-kEu+&m5Ua)@rHd26QR5cn5w z`CYyKbO#VKeI-D@-L_7_t|JhHcSz?YL#8O(UHW?G@daNCsm0YMH z2s4}>>Jz|eS%H&{L{zZ_*fIM%T*kwJNIQ?8dyBXC<=}1! ze9*0N@0RvQsd4+|HEy3Nd8;2YK0VP;Y>tc_;&s>;vImx{~$zBJhrjxtXw>$7+C9~>-X-P- zQWUWa6N^?8LWX7IN{y|cCVl-H>4O6-$5c-B5IZ-RLcIj@*i<(gOd-w$i-aQz{MHzr zdR!aHjp4g~7rGd3mIKsaV|e)uZ9M71bg?n~7OXo?1Eq!)W4}*J>PdbYT18F8(BaRn z08&GC^t&NDIx&S8;+-{7!nLWzlti~vPuCuC7Ob+8gZ4%^Hwe_R8ULxPB6naXsG&RD zNCIByjx)GAVLe5W&>=k77Ha^HHRcIy9t@$Np^dzu?2w~zM-1`*GPuQiD8#FXN3RGi zP~e6ZkRRG5VLrU@9wKC^)yO1!U!p!ht#A)Y+}`!ZN3jnM3Aa=KAjbVm`|8qzBR^L^ z1_^MxQDng5LP3rz=3fp8|GMnCfW0PCX`RphDPZp^2C6O`spttuHZlnR=;E5+sWaio z&3;YbrWX(G(~6-o-u29X?J7zZQULR#e?n( z;jP(4Tx1)=&7H9eVO!BD$WXL8uZ1`>w>0*m*(vj=9%yhpIqBYaavH-YWFp<+g@w{E zQT|ENCN*JF-AzTammF<6ZXFi|d~%d~Eh!O6UGKu)GScr9=>lVGOh`U)#rs#T&-*?0 zX#HEK9X!*&R9CvVT6X2NVm57_fPaxbPK`<*dmVi1YzMEuvV-Se)xl(XMIT@9b@28% z9qe{lps83^&vsclU2^qKPQBhbT3(Um#h(9sBtA4}BwoibSmUmQ+r*Gzlwqj$GZNPH zBaFr9V~j=ae;o@KPgOfV38PqVSB{65{vo_{D7^F{`(uN2esiEI>lhVzxWaW2dl#f; z(?~e7c34`jeZKZ@(&w|cBi#OO_Vxn5JtUpu?}C^!wNk7chARJw+$p^D5dC*3y!049 zLch5D4L@@GoAA=p{O~vR8+z4|UX>eXri-~a%EcQTZjN%(E~)J#FqUsU7wbvwve(SR zq(t~J8OC}LG-Vk3xv3aUx97)n>mO=mU%_j~#KORP59WW{<@FEq#OK)u;5<-e8+cva_C*WG&3@5nec9&Qpq>tWiukq*8 zpYNrM)yC~a!+b4PJKm$~y+?A_=DK7QcuAMj191x$ttTDv1u({(_iDF=ik)wc2R0V~}t`ZDRPHj*SeeqUNA;WgE)34PnPcj_U42Qi8ODN_)%T+Q_(dt<**WuY*^V#Uh zM9w0b`zhG{>W~-?)sk;e4i4%J!z%zea7zy>)?qKBA^Dt^<0Mphm?ZIU|FyuMPGqWa zCU%72^jWTdd36xp*1~&_s+=(zaIWw1VSAq09AbdOEqhgJ2&^rezZ`3lxWrQ(ss`#+ z$U1>-HRpNkYS-y#Faz+x&yR`r57qYt#o#m1BOrc>L2Xq?Q$oI~pgSzu$f&O>Bx3Q9 z_lkEK>#{fcFfpc(RhJhsN+Dj(!F+y!{4ft_$^a$I*2B%d%Y81En&=>3LY~%f{W!?4 zeiF!ka-7eZp?WblaLeWAs|ZIJ#cQdTz)iA)tgjM!&043Pa)jwJ69U(-`$x4hTx%xs zAs#1n|0tOx&D}qOL?*4xssC~5k=H^WuO&@B)bS2f>v21FyOF)TIrGdt<;|{Q6LbES+qlg9NKo#ar_YxKTlmFq1R{2-s}76D zyRFXZOlq(5BS8x7$8{sq@WGY`cfQcl9PHG`N{{duk>}mG^YN~;S6}Q@Tu@(u%3k?o zC9VD)5LHj}F0yDkDLXpiYB&dL8&PF8Rr zDwv+)adD5jx~t8iU_}ZmdXKENE@NYn#6rsEpPp8~dwrV4ysUmP89e&8(Z~EY@|fR- z9`oDa?6>OMdil2j{Z_ux&oBS>i9;_>cTDeC$x%vrAd}eb_JH`KX|7D_-L80dH)1i( z+6WymdeL$2e8_6}pq1}TOQ8^nXf%&mcb$Ya{S0!ev3{bLefT3>m9}*%5Nmm8UR8bn?Ihb*WJj&2WcpJY$Q+S@zEX9kU?gjK_qBmN`b-q|2tmYkQ}q zc`D$f2lg7hMs?96b!?~fjlNN}_>sD{Q+r3AS4aQN_mO||edzMRx$66%e(!$i=5qP> z;>2Wi>z8g86TBr{;$EZE@C}v8@L{OaCmFx_f}d6SsGrotG(J)WNWLm{5HhlUEXbF@!a@? z0v{==;HMC+jg4Ch`l?QzoRaZvS?uvcjn?Y*Q;mjSeNvGU|9!@rHeP!<>vmbZv3z`8 z7NZsTp{~b^1^>Z%WHHt}#$q%!JjO~iYNC(zW#qBG3_aGD!OMx`oaijKqG+>9b9!(PLRw|D@wDoJN#5}FgP+0|F7NZ}b ztnC8IwMYV*ixprFL5vMDV(KJwp@V?!^6zQ@Oed0M;W9_m^Tu7F%w0iC zj;9q<)~!M`q4rw&9+@f#dZR)HhYMVJ@a>Bm8A1t4nFm;fYR9&_r|NEtm$L-|l%J4e+hfO4}_k6Y6_Wn3^W zT6Fc+khMt|W^r(TJ6`@TDBWr{r>dySnwOMox`O_7}iSZ$v%u95-HgsLoZeFh0!L@8`l#(wUrS<(RFlx<**0!HcqAB?4q-2!OMd?es=7oZj zH*~YSD*jp>d)G}Bn7?j&{!N3==jS;$?S45w#W%Gz@bjdb3R3)Bchl-`^Rw`#-55=U zTP9?=Rz~?wpXqlC`A(iaB+oX5_Dtx*=$;9E%DwyeetG=P$etJ^PYKqE=`wOjWks%AH_0z3)qHWO2XzaqSNb3U0ymHBFpVF2d`~>jHA8|8k z{kZr0QSbL--tQ;9-%rc$BkND!d>OvH@^_i|XIVh(0A2P^Pf?_m4&iaEZs0w!54^dM z=D)`J;S$nxCV$Gl1uj!ehL0&K$PMVuZR=DRP0ne19o*%nsft)yUT^xFW~DHxJ)P;Y zNP+(AOfTnZ_l}Z+jOL#HX$AN6?KYp>tafi+r8i_FUN$}QUGuB$4;1jeZ7n6$%4GzT z{#voHIj|jrmktv$+P2RmA^Q&}&qC)pp>+_0`UEUhntP?SL({ z7LikRr5&*F%z5ss)Xh}eBdsG7n)NQR6*=%a>529TayIKa^R%|)$=7);kqbzMG-kv& zFTU(uGe+Q9xADJMKi6C{By7VI^J>I!`+f{Jj>SCYz`1S9S z3rE50+YGvTQQ*oj8~$4KLERQv^e5PoH~2a2z$>8*M}G=D$K6HDBxeiOPCLhe>riF03t*-) zaZm6`y!noItLqIq-Yu>-&+%?{y?)30gzNP=-d5M!>v;D%-hkB7326pDQv(raJMBeB zQ7|Ls7U*dVq(7n0nYsCn7Y|Z8W^Sb|!NQaG(DL#BE>_*| z#YM#WLsf5AyPe4o{JZ$Xyy}pPj-DLt#%$J@c^U~~Npn06_PKl6p7*G8b$iqB=Sbn$_LegjFnjK}U#wqN)E4uC3gCP}5UM z&lBA>#H{W;A5?UN!OCudHn*86ya>fCE3f9+H< zD3$#2m6cTbTJ81jIz5adFctBd`-;q$592`;bZKkCD+gm_jImDYR$)IeJt30 zCUz;?T#Eg5G&j+>((U24z(ngnk~gNtmZfaZcuv0jVfVrnZ(p*4#7E+*Dx2vf||no+>5X1xtFb9YzV2n-SYAFn!VT2 zvhoS`nkf)~9BB5}7#l+J>@_FU5wzEwR7bwO=9D_d+G{!_mDgUg{8|a{*=wrBQ9)d~ z90ze%5>m2$61i55D_K9C-^iHo*E)yczt*gg*}$~RgJSJa0*Xh;#U@5wk)3bT zLV!vB0CrDqh_C6ym!sRjZSgfyKkZgZh8$$)SNKW@v#&p-qJ|+P;Bu^so)uZUJVM*8 zCpk$6QZnIRX`fmkLsm%}7l58o^MT@2eASq1+)Z!QI9$JgI*S&T##a^M$g%)-CpcT6OXhZ^aCDr-r*(m6=XLcD7Qx;dzb5 zJ&1S>30=HFw8KEM0aB^q2?8(-9?5CG`%xgvZ*IOrex^15g1W^?>omClLqNR0`}eUI zefC!+Z$UTneFfS=Goz8WxMpuPtLB9yC%>w!<_Wm$hDusuYkT4i89En)c5o^mJ|0*t zR<(<%M@Av>8hrZK&)++Xh)`)aqZx;zrz;;wQRuqg@NjjW<;He`>-dAMJ0Rc9L3`d7=7&%m=4IzN)NU z(n0i{Xz#3(W{Ko|aM$<^f_d)Gb&V0zO$|&0we7p^R%aI24QF)>>a){k}2aFTglV)_I}6l zzM8xlZE;zPEz))J%Fq+J(X5j*revKQ29ZLWUm4}-Cr7qO{hUPKL-eHP1u5cWGdPo{Cc5-46IFXUT3C@KkE)`!mN+I~4?~2YRjm0r z+4J-O(%_@y3}c;aog?+f5@Fz2g@ud|c48e_2)5dJ9tkSNj#rSGBWi!=6T>&E{Y>vk zdSGLJ#fg*JDp>)3l_;f*1=2a*lhFoE8Ev4o%;cxPCM_CI;)cUIhoxoaz~HuBc(=6e z)%b7yU2e5Vvpw4L?%a=DXX3lYgAx0X^<2Q)1~nMc=Z+ZkN+fU3_;tSE{$;WRZ?IB% z1Uw=EUzdQ~J*De$i>Ph1u|qm>bbWG;5NSC)XC_8ltrxs);W*n{oJap*OpUvAIm^Jx zJzTlKc32ef-LZlMEL5>lD?BOORCg4`?HnncsIEJ}gI49DpRz<0h{KoFvGks*k; zwmEjXzba)(cU;%pzqZ-@bh8pZ<7-TZtfjoTdMC(sn5%AGMriY|mbZ86uj{tR$*gJ^ z{aKaQEbD4lQ2Vo4b_Px{+5fm1F+f}JKyXUdGYOEzn=B$-I>0Xh0jXN92I#`OlMR?1 z(3d6q)N}$f9jv!_gHNiY`w=Ico!d`#3Blb4YkcmqqL#_J`mx@Ev(G*(Ky!_p`AVyvoHB1Y4Kk)Wh2u z8Yt7feW4ET<@$pw-qrmpQ6*ogoR;I4!O=QdJ2ZTG#Yhm8^UcZQe@MPI+*6yauIqTX z@tEJ?y4t!}RFjSKGRyKebgUTven$z4a;rm`LT0P1k2I)tmo}&)nYD`s2|M`%$6ruD z-xKw%8ezXi=)r)gMp$%swmC`zkN-g%{gB!*?!KtU>%-|R_oRGm35zNk#-`Vqb=Udo~QGgr?FR5pMW1nwKAF6}^~v0oH3vKpJRb7)t%vu{o$M}h ziDa*=Y4cToRCx25P^6V|3s?y54HI34uLgbMO*D~)X#;1|(&(gJ=DO$#-s)xx`wC9~ zWcvHqB}ZPyD;WJMD#MGZFu;$W>5&$#m32f9>PiW9Vc{jzZT-b#)iiq|Z#AoAU#W|I z$D>>=_!BEpMXF4UE)yMDfl$|UZZ0TphmJ(QG9^p!-&dXF1geZ!rA*wQj zSRTZa9oYXN0zdCD!$d^0tVgw3;pqEcwhnCJ>Z_r>6d`?tWXdat;5kG5q`eQSx8nY^ zf3xG?+aDbkwzTgMX?Pr;*MX&fZwKiJlyu_Wj9b#+Mx4#ZmItW+R>2AMcv}TE&u7XM zOZo{KT1F4C3phOz?hu{WCO;jK%%dyVTlE8vdz&*{I{|CG`p9t#xOwO0LW~3G0|u4n zS%Y4XcMhAP*;YH;ClafDq9eU$tI=*YowWS_ZD&nw!hGR*HWlIe+mT02Ak~2ju|+1%2mPgXe}9yzKYCqC(y{Rq-Bh-r=<(e0|>W z;(AUi)9*d4mFf4M(#rIEpOwm_bK+!s#UsdXbo1&`p&`an<>_agQ}13g>jDlL>ss_N zdK}aEYKrGk*|qmCy5w}GC~eF*<#Yh+vqqTtnG$x`>4LPkL%mO?y`2LuO6os3_@U&a zXb(OkfXcH^5g`wJNPa(Pr2EB&-yLSpx(Fpa#VgV6gVY!~}o86Uq5_D5uD|p>> zNU6)w2^Mx;Q< z;a((!f5lZ?0kVSvYjVT0iYg6s&FAVeNRh9ZPY^ZBDORt&29iP9zka#TC;G=@+M5TB z$ArP)?fDt~S3fypgVx@LJEZE7YnJ)%91o4ZAo0mN9n7lXgpAXWc}|E}>FXGi$^KkZ z;Avc^L~(<3>N0=i+B^LZNYophsErL<2~Um>w8WympLc!57lfNUlyA%Yt*5VU2-3sjqI)JB!xk*u`ate0gNG z%m{*0{4Gh-(5w+!VPZ&Bl(TuqKU|r(W`^)G2vQzaVexO4gv&fN9|my|Q%7Zm%ly>$ zHmzA6?RmTUeTe`OxbZ9QhSNS%G! z(bbx!Z;8{{?A`dvde(8*AdR?A071wtpO3LlkJ9i(z>Y%D>jW#kgm za62)USP3vRc*$xwL>ABi$@h_>SIhY-Da<;#dJ1J5Tjo#gl>6)gH*(?&OLPR5WV&hf zM`Be<#Ap>{ZiU;T~Y!q}lc}=LFqyw3|L_+p=TVgGT#O5zC**mFz$7R4#$@ zfl#uh?6JyU`MLAWYSCS%YV4i2K&4ZXj?3m}QmH`!l3U_I!WfYL`80`=on{4gGIZjR z=`goa2V08xJTctSDkf<@*af#TU`VBu=)A4H9mK*^prz@3GIY^fa;HUojR2~*WG(@s z7`&t5^8+nq{hoz*JZaB|@OaankKpm8J-1;aDXjTdKT7G0GR%45HjH5!*m^d&J6dFn zGoEYL=|Z{a3q+fF57h3W#`2^pd(Ah;>PfS`-=5a+=!ZQJ{57Y52MKjJ(IF7F$1Zxj zhmf4C**gu}PS0={$`I<1(Di#6ko(`Me9kk=w3vMN34d9}+{8|{XbDj!rw-ul@}~bS zf^{Mmv}->y69wy{8(uIr5dJn$9 zg9oC8zx4`3s~EfsE9Hy4mdAwX;!!P?#ERy%f?g#C?Rz%@z$AGhOx4oEr#+z1@PpHt2dZR#I979wi6w`E2khfF8zCzZx|kL8UbcNd zol3RCk%Hjhu@SdR+;*J?jJB_;bw*0{$Q=^dhjgNDu7kBUe| z0dpNVN{oDMSV%bZRCrcFP0nP;OX6bwR4f-JVSObbg4$6nmooCJEWR+;-o8&%d=lRz zH#I=BZ;RD4EHciZW5Wx2?lM{FStBW!BJaB*Qq^zW#71+T7TzaCR)61YkQxHSGjj*G z81MzNylw2h!{^McOmxG0*6+HRUysU<-=6NXr}H<@o*uNP=iAc@?CFJ5!#gyyJ-o1J z?j{w@bIhbgCyKY}YAM-{PUo+H9<7mUuNDR8tA3JvdssB02KHC*$QDMi6-;NUid}ta zN;m2A?2mI3-@IL`6rFIl0PrM?el?nf(L&0d{FVT9sM+(D0lzI~v^o?#WXjcBoQ`nX zSL)O|tQviRruXsJE&5!vVoRmK?(L9a=FUHVZeldFi?be_E%|3fuh^1xzMSw}IbRCl z72EYQ6`j8TZ7p>aIg@A#p5oT|3+#s{;<7i~#ou`SbpA?zpvj7hOQZf>&fk)X{HoWK zO!lF#VuUbs5I3XtW|n$sc(M<9))~IAx&5{5aHFD@1Y;kP&NZ4ff`(3>!~!HOGRoRR zRF2~jOH~Y3UofKMrJ%`qRk`tcaXNyaltwPGK>d$oC(!Zyt`xmZ#Y`uQ9pU$hXfcrP z`4N9S+b65~9f%l50`aL+JowzOHz08wsQ)q*C*0c~&TCROu_TaB{? zsv)A_R{s@0Tm9$#93*EU;wuxqf1)YcvT2#LOQ%O&JFOwZP2otX`9i{(S9H#AW&AtT-e~uYKACmibJpH%+@Iv#TFeQ`fWD76z4t_QZB)9o zd=2<^sOLI;Q!+6!BFa)4`1~wGC7nhUWRtBLMy7X@DdvGxI77fh=Pb)y+Aa0J#YyCS zX?~*NCAwv&bLrCiL8Ve|{6_1m2jzd{qU^KI(2R9TK^5!TDcA1IVNR;-8q~9hZ zur+*45xChr!;R8%Zj{*V)k*B^6L@Y>&vGfM z%xKlzZknIC{0;2_84rOGHJWwFUMp{;bnQ54)9}bFYtJ3Jbf!3O zN7j}RjtJo0Z};@?GI?=p%k}R2k+l_9ZrnOsl$P4-B0$zSS+mSdZr~>~{AQc{sTRzGg7QVCKL}Ps(Yy&oj@qU3j4>`2@R}gnumPpG4=~*cGo5+uKT$B;WaoKa3?syU=0v(g3KP z!I61}bEcOw2bm(8dDP+rLV=r%-34I02zBY!slw1I=$FGc%I4ysT~qA@f@tA z^br`e!XBg~9OB|&iNAIf=5VI4r_-n=u=lD$h9SjoB3pRPm@!%fO1 zYan%xr)J+S;k-FP$!5MT^QXCH@RN@;TQ;2@Jv3IG>a4p z+JqcjQl9VKE)R{U>zt_5h!)mp*y9w_7ahy|=4-cV_55&%l!Zn^{jkxbgasrMZ)NIn zA`P(6j=oDck`g48PSKL^bWb3SL37SG++w3=!i&-7x~Q zUIf4xcXPb*mc;&rve>7Ng!X*AlJF(A)`RL7Qtxl`6=#vlvLj?YAu>|q8HtkhI!!_v z!{yG=ms5uNh`5A^^b9p9BWhTqR{v61blN$uRW_YwIccHWIm{R8Wv^*;D)2fubQ<9X z%}OMLoIBu;ueoBG>-t-G<$FPeUlGvr9s4D`8k%#(t+76zT7x)k%bQ_hFy5x3{bSAE zp0_z(u~lY0ParTVMoi_N?aQ^N%NWbN#ac zY>NHWGi~kEJ|@%Z))gKsw$JEUJ2f@P+q*Vx z>0xQJNQcFR;?D`pMH}Qe91@2&c=PKJ%os75vR2;~aQvG4l+7~b}(>r-Cxa_W0*(i*Y|R(GG7EXy-q ziqeer=~m9dH{cf;h=a#^_Q=DSy{NUNl)QO)6mAf9kXJsBmkz+H0|f_b--UJX=+t3M z#Lz{v=!D{5Sd#)7D|{xC=hB@SEOc)tF+^_R1;Yy_Pu`1K!^dm#K!mwS0d~#Sq!+1( zGOPWXQVJsTy1wTqrTQCegXjjbtE`0o#M{LD#OJU-!_Y*1GNGe|4tr_QUKyhgWa=1E zpHN(lU!BCpSHy?C>M3kq%ZANQOpwGmB%EG+f!pI7u;HrpWu*w4Y1y#3iD4RL>U1Ju z+4}{vNGi}QU)il#K*pB?O`g2fIX&V&fqspAjW>Kje?9@eD(5The>|i18W=5|iD5ui z@)ZJ}&r_||Qn9T4H}u1?(|iy&?M2^&X_mhhD=hcS5JS0pk@s2aE9jrEftHKr9A9rt z*Vh~|@n!zwJ<34hvMT!@HM*H9)n8cgd!%2eGysGyi-~S~51-Avz2#b!Ao;^XqI<#Y z^AeS_QASv*CZYnLX5`ff5(bpEq#~PBk?r#nn-44P8vVqkeqx|;sJlz({&4#h{Cd9v zthmw{@rqXEwyc3bAH$@(u5i79J`T|~^-B(7%5n6}VN zLl<~^xm>f?Wr)(}^TXx3*8Eyw36&3*4DRNu{G-$3*7CGx&sJO>GK*W)<>|6kmZz(- zx<9P3Kdec@O1Wsf$#|pNkV1ufGM#$b6sH;)Y zFY`;JK>g7?s&r3~?I7|xGgRI%j#=Icnz~uB z4Ifo3`9~BzF|SxI?<|a&ysV~no{)~6+EtnO^Dym8y3VR8@e7okK=2>~}jr1gN!&h{EhK?44lAO)F3}g=u4)_MlyEi6YDZzcgNY zUU%1(l2d%;^k*Furn2yCU-ci7~Emw(k=I34Wfc^_x2z;mj#ALq^Cc}rP{XiU6Db? zq)eA3q|l{I9SyznT#(EjV1YpkqLw(?)L<4Wct3X$Blz}Z#6~`SdyvyUATy7lx?)6o9VFxh^@f+BYsERmE8)I(jlSJ7aAumZ~D|wC9mx zsmBbdEuE$+0==$ zf4nqZcIF<5b!LJPgFP%4F@dN0nD3^5HwS0!@t+=c6LaDXC8u6&~m?x6&8y zWHMkvfJ{hRvMnKW-+R+F)DA=tFTY%~zzHruQ~9Is6nb{m+2MqA2*Su(afUT<^&!Sa z-k&JuT^vO`*S-Npfs>UpW(x+7*m5cWgM^M77_l0`%zASqU#ugw$E{X(i^Mp)lMUJu zVJo4UhF{DX)Yhe3`q(OPEyiVZc{IzOTGn3iE2h9~pPXJ7PBx--UvZNA0xuDXugyxO z*bj@Jk}jCnBX$L%mMk>cn@*ZNyKcR19k62X?LwKT4ijy-)Iu4^qRLu8dmc;$EX%+-8@H+giEw5|xIX?wDSW zP8dBuak@(=wyxAp-6Ce4&nhht2^H^A?*VS5tFJ%DUZjq{;n0HKdR}2fg_%q1YZAh+ zH664^P*vWc=KZ>Wp-*NLNj8p(Q`yt3it}Tjnd@TmI8HCo3-n0X>8qx{^vRWl5qlSJ zLe8KiuX5)u^bo`5Y~}V=*~-i8tuy(tw^s5uJj2KOnpH42u&=Dpd>}v6@d4XxrcV-I zV~T1ueP(%qIcn}MRHYMkcvXT`{R(eeGBh{wX^DBS^VzH@Fk;4tWP_v0Y>Z@wEXnyH z>#w=pTJ!GT!H2T85OxE1xkJ{Ujvz}JzXOrKP>-a*;9+EnF*2)pMSPE`5Pc#l8`xJ` z7@CvseL%AFI{Kx$pCfK7f2HIsw`6Y*xzzPFvM_6hhx=B%t}Z3+n$i2^CpkjBh>EF~ zr`x`oEYn94>HG&|Os(ZUcJ4CzU26gdf17Oesk<6T01hzPJ?{2Prtn8vWb)-hS;e z>j~UZYv$`DuUkec2UntZ$N*c1`3uoitXy(j6I@rjW|!M&MT#YO3V$hR5D5quH%-O; z<6D`s5|aM*)dgcG@J&bW!&+w%Nz0;*Y`~>75n6n9{Xld4G)GfJ-oo0_mJ#D>Vn}}1 z6Rlh-nHVmNv$^tP6QqUDO*Bxf8u}qF78%UFKK7J#yzfA!O*B1-X0j8Zt0jy22D$!3 z%A$EInm@T@$&&6f$1b@_P|4R@7rhXS2q7PgWJUAdpZqOcMh;Kk3e=0d(Mg_I%45i0 z^8)JzK%$JQAh}}{_`J$h%{n2(qLM&Dw`9piKH5}m*v?LJUCF#=F(%u|H5Qwp2Nl+n zj5yThFRe*P2hJB_W(dSgf3JX%6^gmM_3MyQA1dSg3NHG2B-mtwz;N1vM2U_;0mKk> zrB{}=N!F9;m(=P4$u_>aV3O)Gsgu({|IumTrvpt-%0rKFhO1CEpYLkFOQF{L*j(R{ zDPtx}5JMUDW5hR`ogdPbbv8G;M>amF*?#)xae0%Wi6hKW*-sE>iGCo{`_xsPVgU4S zftJ}`Jjd$dQb)1N6Zr)Y)=mM`ojT|Y$}fdb!m1>D;33}CDN>|$_6W6>A^M{FfV#Xy zeA)4AEjSw`%}m`Pbdf8CIlItolaRstONb>Ne3JrM@Pi_g05qwY-*#J*^M18g2u`#z zgqIscYof%GwOey72W$Gqp>dS*8$NK{a;eDF53oG}(@IrH4gb!Lvt0r=l z=KPxmh63rvl+5;FKuGCylX?~UJfojJM?>jh8NO+V5E*e1@J)Wi3efblijqC;b_3Y{ zCm!s-OolU@%VhI6IDrO#c%A#nILsDFLca3n6I~IGyzBh8Fi8nb4 z_1+%mf+FmQKZ%v&NHD&NE10X8y*2I1)@zr3k*m%sp|j<-v+9I8@=%gcN6@S~rH*_w zL#`1=fmxNIjzY7_uZ|+KDyWVzW)&C#IL4Y)d(|=CteT>qCP2vbj|~3lW^J?Nd-F_d zw=84BdV)XILy1NBMYzZ~zB?qF9|Vt2R*_Xb+>-ZNQXe`64|=N1F&@e2Hs z0*o1olF9>)-4Iv_k=K?)@*{;DMQcX~T8>*U2G=s09k8Li(ef@*B=y^MftEv7j3Rv5 zR>CJjNS@XkW1hB2@2~a!^!>>ptFh`F>pS>5xR0^Mz|xM-6>HT4fl@o{J`r9DzZ7Wtd>T>W%KD=CE%p6yrkZ;dv|N|wNKM$4SngBuAvK{n z@oAiIp(GjpjY~V8#KrWX_{O}P_YAG^^u<nhn{)JwGn$reFh)xA38Wn@;)S7_0g+? zU=8`?joB0vXt~yE^V73yFQFeb%t+~>Hn2)PZG267@lF~;1;-?_C-v5Nw)PUbb``82w)K7*w(6OnDNqY1ffH8Ao^aa&kC!0j* zWZeP2N+MMIS@qEJ@=V@t?(ut7#|m@!_j#jvAFwVKqYY3jU4-<^F93)AMM~KC4{T5C z`*$w8LlNM1k_ zZ`mD*b22w?k`Thf9W^D(?nsU${MVU-W4=h*j+ey@5Vl>yIwa`#{>Ao9eitCsUElsY zr$G2FgGb}5OdJe)GVc6Hj)=U@)KJEgpaJby4m5rfnQX7~?FNydOjJCMJMq_PvM`E@ zThn{OK>m8!;PvhW~hG2%z3B@leo6gYj=$9}Wft7xg{qBygKn-h}W5kDNhMwb>yuSv{ za$+x`y&B{{ekpUF+Ed~Mrk5hnRuG-Z^WmOc(-Gb;cnE@j-#M{-QwH42V6nO zE81JYUO5RhCxz&B3@35;1;JB7?Ik})?9G_zeM>@z)ab;lg0yU^w@;{$Q^41zvrL~y zdq&Gv%8is8L%X>=0MB%7{lVo!j~_`6RjtfjJxoHtn%b=wR_t0SagKz3$316p><>Ah zuPp5pMuK3l#MFVtNxQdA8ZoFm>WlcxeOcIqS#+Q-r3>4yx-Iyr%u!Ho&*V^mitg{0 zQn1^9#DLw%okpkpEyUI-|Kki7&=B)+DH-FMq3H137Q2`e^6<&i_gFl_4@e%m@=npEHjBc+~e*Gu}K6Ga2JX zru|qC6*A9q{N{Na18&DJ(`CtAbpegvkIkJ+7dZVp6=F6sA~B+c9<+Y1jh1Jcr-kX= zD;XNtkiBGHcUk(MRA~sfq0)Ar7x9GXRG4(sn!}OisnJv49P{MH$;VH_z@Wl*X84&v zQ)Q|j+E+DE-^{v{yLI0ECg${G&+DJ`#+-iaVH%Ll{K=@9{@P8I9=|aR&D{Aj?0IJw z2vTjS`JD(f-{n>PRX_RFUHs->Qvh&%Mfd<0KNieD_O`(*7ASMfOQ2WBxY2Z<37tc+ z`md(Vu}S#e&wMu%2FhaZfLb@!Qct3|y?c~w1fAu{oZYgEu%{gYP5k%^s<&;9JfwQt zqN!}O^GR-rgW6MXIm}AOnWp`(NyxPkW?LJn2v}Vk12}9Z{PI#;)S6ju$ z;81F5M(|4!uSnr>C8NK$=lH^l^x!eoMpu_P24Rm6k8rJF)5|y zT1UljxSP4FN9ZHpm}EFBk(hr0egbIfWMFlYJjQ&5Ww>5+II8nl5hMt#xkH)LOcfzx zR}d`O23F0&2U}09Zso0_jF^N-XNY4hQFv}+BAX!Fgb zq#tD1K3abf3*QH&uE45E+h0hxy=(X(r`hcqm6`B%&$$W(Z4678tAR*XBU?Ut`aC z>MqI3svdwa!QMve73=w~LBj0wzSF3@L5uB7T$0soc9~C;eS5Da`gW_6-^_2H9URx0zXez7#|Z&wt;ox$ z`uJ|4#zPDIvFCEt-iDa_3C<67Mk^Ax%t0oM7u_Es(+7O8yjacl-^QMksgw^t4(sZm zvaVvO2#gv(>EM z)C&off%a2!sN)Xe=A^#0_&4eIuZlcTp)shbBVfjAhpfL}?E8dJ(O>x;98fjS`32!x zGXPe}>*YA~mSc{I_#<;<9?^wP?PwTiAx!3Lg*2KCuqPKm2nnr zNsUoE!#pg%(JA{j!U}#+Eg6B=;eBw2WMi6kOynojq}djfO4kn*fiCi?Zf={ z5u@#Os<2?$uw{AFg6{mo-|@~ZzK~dUS;do)m7WKE1$=1DEOTTxCnIK#)Y=iYj!1$W zYU{ToCTA!;G&0>kGwV0SF8Ul}1m&dwPW^eo+^LBXnyDWZmLK;U96E8<9kEy1_hxGq z5{CN!=`pP*u;u9hm?g61KZRB# z-b|zlbIfJVsxQ2ip=VdVYnQ~Gvg^voPSi}_uGu`=tvCtQhvAHJ2r6W2-dyIRLR5hA z!i$2{hOKm9{@-zh@jQ21%(Lkv;3g2ktehJ~{A>|Jiq2EwAkrfkzVwJ(-{UvI@WeKv z)s|X*Gnct&Ek;N-gI~6@YQ))%%pycPW2bXteRN%ImX%nN%(~BOwJt%OcQzM47m8!E z%N0O~civ%a>fG0ADEIMl%mKqKVhc9qe#LYUBqGp?CQO%)i1B5qL+znwfgo|u zm+{zmhA@}M`%a`X0z30^IMlqyuE0muwfU5;%{Iu?;%P{3$ldty=^mIDVG-)6-ewj( zVqzOBK>$rfHYHw*sD-0;>qz#Uc=6T8A3Uqfm)Rrao(}GHQOgBI_*gB+ay#7u6hd^B z@Z;$YZp@(fEwRolNsfqQ@dJI{Mn64e^`)x3R&0q{dshP~t95Bm&3^y$I$8-cRa{< zxnZipDFb z%>f3OYB-#rVhjmeVN=xCY)3a~7EMwjT*VmwH!>j$9Sk z`K8Pj{a(oTmb)^9KN!L+K~QN$D-6IH+j7zpDNH?+T&dC8LIvPfaRw{WBXA9F@we`yn|T#*DBY6^!&f9{Rs(I2|FVhVS6Q%#w^4t{cYmMF#Y@FOB%$~n^Da*+KDy)qjBM1*yDF`6Y5Zo}jMpE7zkuXx@xd@Xtq>;PiaC?p911^8!Xw4M2|tapihSAx(lp$N zHa(T7&IXOQLvT>SM{07+kv;Ok=y^!KIi`KLR|A$0#E<~ApFU=sdRtw-_-bvB-pp1% zEP-aqhE4XAhnuuFyid^|i_XSZKP(MU?DXH5DZkuePx0BFA#L{TOI^ONgYMNv8ZFb(LuY(=#DX6-V9&#*cw*fYIM5*nAXYF z*+Mj8z~0X(3qYP;gu?A~T9*Mc>PWb&7AO5DKu&>g9l)Psy0nh~VRC(5^=)!}KJ`7~ z`m)sbsO!sC-)7gB$qnmlTN6r~rr`sI+;R1dV zKT#~HVv0@!8rD#l#5KL3fZmgry2p=hmJmV-FAbrmA+sD2?715AD)R(y&}b1$uBiA& zKc+epd@trZ_%Y_ZiQ7A-^O+_mMiD4laK4nYS?{Hf#daN*GIi89+V%NTZ_SS*VMisu zsFdol7F1$%rnY9T$N0vZL*`4uRl8~#>y-}^GT)>PKXZ%$L zf>d`?uVVms0Q+zMs5G?SXvOV@)AHDrF?NkgqXS9|mv{6KI+;?rBg#Q?2w=hg)7&{x zl)B-WB^FYp`ZN~ck0hSp0jiNpqkp*w=`AQWfC^~E{r62VN1K%!@hgXq1lyjieKJsg$dgSTaXvaBZv~&x``HYT2sWTYi z`mw6){%zfqDm5+xDCe_bUJ9A*sKc}}J%tbxNe6zjE18)-W^s{xCAN@@{D*I-du8G@ z2eXYn50+oOyP%1=nd;>CmIu*V<$#OCvYl;dQ_c58*I;WRqE{N9WrBwOzD~n}*<)x=Djglp}*4NmWqpJ_l1?2m3Ug@yr}uu=wm&7gLJr#oqjn9=<+vRbt()_$1A!RKv)ZTdjhQB-wR(iPRY%L=23Hb2XNjJO>pw9%ilfDWG+aB!zAKC$3Jn!0~K2NoHjUK8x zU(aJY@XYgS3@m~m%z5PthvE|Yr1Gj&iWF#5nDpLGVHN1nezQE(C4+#|mZSgme4(*Hj-X4CY zwt#u<*jn#J4T^WDcuf%iY{_xqcKxQpPOrsL#m7$o%MK5q=ceIemEA5JfU?Hs~! zYKe`ZSd*a;K^|>x7rZdxk%2z|JGoD0%Xt;o3C>AW-6q?oJV0XF-@skTHeE}?u@wsb zA(9Pr3KB%MH=D~cE*Ech2?Pe`Jv@F;hkyO%K{bV*40mvhNo5!{Azq#!SA$Tb?;b4L zLo~j*f)NbJ?W3ZnM!-jMo$+WR@jsb6AMmKlI)JnNj&Z@sowRD{s#UA7qoP;^-Kz2D zU?H<94oIE!N0*e9CRd0XFb zYwPpS|}6$ORf<0L9UpZJNIYXFHu^8?7;WZJ+QHSH!j8;&WRyijQo-PFApi|j&s2WuDvve-j1qaLH70< zIhR~u+~*zr;bwg(#9}QY%V&xMl9RIKn!8hTm-WM-!@sn+rS$TXj+jUMWG*e;xrxI| zr^NSeRgV)(F;cg*zKq`IRD|dvLy9n@^;ZwEVKVdvtGmeyXb!PS@g(87cFq+McKmbZ zh7TEp?JoSqbmCV(+jli5V6XMLoX1egBdx&=YluQR5dX1|_!G0aggL}}-yH7MmiA=T z*Uu=N=Ir`(bNH49_ukIx3_N^9 z=hpMoIg*!e|d8k$~}b_vWtDA%X_$`)WxEWrWnvNnjjs0dGDoe6`KJ zA-$5#8f_=uL)3=N25VD(I?8`?3O}o&Ig=+fuBbbQ@!S%u3|vt${)&o;;WJl&<)aCf z6!L#vyQvs&&UXA|3~suf8fknvrp>7RyM-bW*r7Kp0S!FA;?TY(tn zU2;FlNNo#LkHsOG+SN_5g#!;DsX&*sV;x34420XmRXvqtf7bEda=y)ai zvh>Cqz`k0#iOxZ^X!Nvrw0L47fXH$IE#_3@gZt)Gr0jyQXiT%*K%0~{GTF>n+lLtJ z;JS%r2G29abecH+mmK{;cYycH$g&*yIgS|d2(^v4lT4}*);I`Re7ZAd$e!U0&Jou@ zJPF{?BP%!0tdxxtj!rPK(veezb&>4POZ==fs3PSF-%8mKD|>97gs)!Jl*)y-aoopk zp7`<#>F_$)>_~Z->N%!a7{+KOepTuhgVE9P*jYl;8~=PV%+AfK-c-itL0)fsA!15a zXu{PfskXbZQl&Bd!*VzUn#Am;y$&1$7#V01aeM4*9}+8^eO`~oLYm- zW@4kx>E;vsW%At1JY&wh5^Bd;MT1@Ice?`li7C-J%c?h;#VhH;c(-#m00B@w zLVbp1e4vZIVSzpV6zv?#^en9wdxKmN&S9vOC8pK0#IF49!->-OiF4e#gQi|Dt5x-V zO0n!@#=GovbumtHL~&e8Wr8j8J<7HRPN_Z-ZjIMX7_sbwsM9))rV1kMS@XWM^HOtr zAJ;q@rW{@dK)+aC!nQ{`$U{Qnexg6z6i!+fgvoQk`0wfB?`)>93i&lVvf#PhxgyFC zDl@Sj0wq6zsoNgkC0lR=Kv8@67#3ugs6kmi)}ZVvH7F||Q$53=>{Av#AdWIeV|Lsx zx&|G8u5TH^aR<14rAeyybI93OK*3GivE5;}J(k#G$+)fE*MWC+LMj@GL-y`t82=XQk8YrP+E-t3(=g$M2^D zhr=yc2>`i;^v--#pf3L_NA>|p*tJHX58BCT^r#G=AAmA$)m~7ReA3sEM%pp{Gdmf% zryt{bL(e$*dmk2XoyV8}Q$Vc0ThmN!?RHVszciJWiYe_jB$l4fFMPBBKyXPS@HVg! zu1rx{7ojiXYk;&67USIV2!2`4hr~{3tV?6|I&-(Il>3l-OCQBTHxP$*GN8W=kf_!j zM$O963&li%3+xT1F2Ym6^()Q+6DGDdI-VP)M9EJQKN}Gg4+m7 zSy|V1xFlCFIiT>W8hY z3U;-D9bb+kAU>Bd!+Z*K_TN_sg!p0=F?>%x6KN_thh6r8>=~7j=&%B2W?R;*65VG< z9m>QHX3qlg_MurKPPg>-Kgf24nn%9P(96CqM_#_ zWWq2XAs;JJCm|C|)r5;W2^nAR#)`tN&*~+l=s)%nBI_8}*S$UbSpim=WVfowt?)&i__Vz*q(bR<#wB^RLcB`Qt)-aZ~?B^mgqW&78d;4NuUnLEEvCR3}feJEZxF*o*p zZ%JeGhb>yvb5c^o>I~{DksOkGc2}N0-Q8y-iXDA}&SZ zcA+&oK{}#`$8&t*=Q8-bJW%2_#HAvs!bk!w4R6`iyr#P7IVZ&1;_;77$YDNWM<9n# zq`pQ0_b}ASn7?f;RFot3Bu{WG=UxxPXPK7+T;r>P2^TijTdK*u@;UH+n zJ`BEBav!G-KTfQ|Kj~2b^(psAHfxgARCOhG%6z)9p8BQ$MLE*oRj+cITc@dO7g#3K zG12Ab;&@Y9ns&<#9}g32jz^DpXn*AQ-tVl#gi5AQR_vl#w1`Huz^7w9b`;Q#zOwBD>BKB)R^dlVm_A> zfg>EBo4~eY-FT!X&|($m3!qZbZJtkmu`}eGtWBMW-+ZD!dGiS&5WGMzF7&uOA_0Dq zUk0{zQe`M7>vPsQj6#6@h+hzhpCRW00%#02@KIURABSYSysI^OT#xgYWhrspbVcH` z#iND4Iy!Q=?ga*$e3;n~^_=5n^-Zz~BF(kGr+jxF%k=27S59iQ_dz7NIIliW><*UI zw`jhVx;fB46J>?E_C-%is&m#stvc2qjHRS?`jPOB3ri!S!MPvnNw&VktO3~}(2fSo zS)~4*cIFk#yqo0@dyj!|gB&99^DX#Cg zaPl4xPVTpG@*eqs8<_*F`}A=|KOvPJf47j;`AD38yu;`*d) zMen`26mGqb2eY%RKB@bwwYHmrvb_ed@3ZJpN#s3#7*@!-c!0>-sjo6((7eQ~kXFr{ zdNA=k*?AADL1e_D0C+IR1VV~kAok%E(cUYnQfhw)iwb+}{_Dpu(cjsBE$qMhW&fcq zoY{i!Fq`g|Eoi|4v4B!_(E5Gpu|kue-J_mI@1j@MKHAHE%Q1)9d$a7Wqp|b0Tu-Eq zEqAjR-F7I!$P|b2F7OpH@3>OIAIkmr`t+)n`+P-6FYLIjVzRqZU){Kms2H(cc|xN) zJ2UG0+?6SfXUJu7OD>y+g|{CZ&+&d>2P?%ao<%XMuT0ciirMPp9>r|)AjK^Di;K(q z!jIo_0YAPRdihOIyF~am;rp$6F>jW4QvAr)b){Y+Rjtw4IT+^DR~0FZjY~u6Z_<@D zT&j=`$wG!i{z{N{JmsN!sQi339Qrxih2D00jGXMriK#vW01&B5Of51(uSL`0{ptj2 zj%7weT2qIIr3gK{vHLRcPy8Hr>Jb7UOMadnK6z$opQWh3&u7L3_r8F)B7=i&v!oKe zkMI`L55kebo3>lR52({N`&$lh#LTpZJq@Lt^3cw#q+Sm*9ZIT5TeQiU^qoTO0Dq76)rP|zB5h;=0+mem>DEX_`1i=@!M`q3qqs0=<*@t2t2 zb&na7tR1N~)S#7I!}{IFriT)uv@bwI@X5a?2XOo}HvSZP2jIDogm@XrXeu6r`5*5h z4QB|JUT71-ZQ;Z5=vE&FFQq3BN>A7oq6Is36v5~XCbmEh>F%oDM-IwT`=xIiYWe#Cc(D3dfBa?MkfGTc@%R0eyglEu^~Yt1*%PGq?v6 z&JnMIi@J75{%FzEv`|wKyR*d9sc8e4CA5l}P%e)05essB#`5Cx3E*ao50s1bd}PP) z$y4&`TC)^9`$k@{Pvx3?KllW6)!~lVvbIb+QQZIq-Y)T?`Q8@E#6#Zx$ixFSzCIK8 z+xVtT+-Kwaym+3Cc6w0;r}3l2Gkc9LSmfLy{|C7nt+4u0th2PyqYSZva418>ARMsa z^%C~m@FofSYm;eiy?rB;T5@v(HTT9q6s5rDLbug+8Qb zKpbZWcOIdnI^)t_^S)kVy_BUdiFdJ* z=Yo630rFv1jt1F+@Y}_yDIj0`$uzeQSC8{FY4o<)o_yNX0jS8G3<8ELo8biKvA(7E ztXvAWxVYmQVb-rvLT?NgkR7mBMCFo8Lzgpb^7@!wuh48&ijHBw5nZP>pa0fcM@jd>LmOkDY zei%JLrH}8n^l_p}AKxt>E0QSSYg_n`C6S-?NaTO4ZxRwY!b9hHuw_mvhq)<3G#}l)Pl@KQjlBX#L@EG>july{M62kvJFWW~ zp`pLrU`=z6lF?gXk&7}sf(-3e|GayGP}7%HYV$%v*I!x^pHYCPg2plZf*w3|Xn|gK zC4FxdhCO7-A3bVDIFG=M4)0H%8?Bnk4>^c>jgCBAH_mAWMuhd{kdti5?tC`hY0ww2 z%p6T4$HTG}rx&_+^|^NxnCX3>VDVjcs!<2Px+ZHOLI6FY@fADB{`IXS4`|AjfiM7D zNBG#1pr;;|Z&lDP@s!6#S`ECpAr3d{?9$L(`DkRj(|u-o!LWw3l| zJUJO;@XyRPbcjW*(HzC+ncf{MR}k*Llw=ajjxQ4x>r!tj(pD%$x= z1wfNDmbkqzQPMI9k|s)%yGAK3WKrEIx-9jwjt=hVt{t)b1(E2j!S!Mrjcv!tt-e*v z2(S7~HtzaD;i_)>Oe0B9pr03a9re7pE3RsgtU`eZd5l$G(mQK|vZ5<)bysZwI43Sp zF+aZF(PRT1(YKDCcRLgsP_TMnjpm8oWU6lwAo*S;7VJp;STF{FXpCr$Nt&aaYp)oeREp5Y%g#CnZv}qjYA$R?n@-z0Aqx_O0OddN+ zIcxMLb{Gg>a^7-Ue%J?xEjGyd!!Bg4!}OR zem1g#>|s;a1>NHEM9JN|Lb`+`)VIn=z%ayO&L0xrT9EBga&<$_v-xlH(=teP7C&L) z{{cUt#PSnL{#X2jl8f>aCJH|x|M~d|1;h9WCFk=KiY-53!oR^!C{}(#;YIlgMYg@- zi}4dkg`Y6Vc|LwZG5myy9zUUEI6t8{!%r}6RCyskp=3Bep;-9|;IAbYnF#|38J}eZPqTv0u!3igJjDt=!wQ}?ZG z>vwMT#PGUaHJU4iSSq0PnpWC}oz6jE5Q&lvW^Ce9;3V_sfD^3Ed9yc-`dOSWSGFYGPx%yA*M(0)`j!?_TN^;ygl(W!hswYy5Jlx)VZ5J7A zO!J~9dV|7#&r%H|>?3@@-LBbg>wE6zZtKI5HS-oL9;t8f$HwO{jTm}W4T}J$hjUXu zoWbGQ)3MGyBOA7mVevc7ngU{YSajFSA)$56rjXi1B(!-jw3Sf)2>JD1LW-PF+%pAt zxf<&WsdckO*003CnlgSx!c-GC1tif=^dkD?ep8?6K)rUL-s=FN&4VGY1B5aipfam3 zcmaJ%ltug*szHXD5SJ$Anfr_QI4$#mE-?6>y7ea>ui;?o0|ZT6T80uOq^0;~8;ceu}?lcOi8c_2q_;VMf;R zPd^s^5!z7PNZS#5gqk8!WHVXx)_61cB?wO(Y%NjvZo8kbi#D)qiJ9|-Rd~BbkDl$# z`4f}Y)gahyF7V$=GE`1W;oPAVPIEx^j_3eB7mf45c&pepzI~>U&SUMh_mgB0iL4Sy zBvaisEm5NVb`H=pr$u{v6axjp_4Zlco=^hMe9>uMqRPwnm5J=WZxRWMB_R=AQJMM@ ziKc1=rk<>$eeh|c`QgGQB%8T^tInA$^bu?^Bey;VP6Llrym3XhpA(Uoxni~0a(mCK z+Y-}#Jmo6J>WYK=_$rxo`Wr6`skLQ<(AzwJHo={Niu}*26MLg!Hq(e&*TFwf0lVXGrWFHtI&@Y;}?*Ize@vV6|)j2HHIv zZ_oGtTwHB&#MEqu9~mS0sEiRUB4Z>U?J!ng911FVM0ZH1?hp`T#%1Cvg=gfHm=0JK zE^b7QnYbKFp^>xXV7$=S+F_P3>Um*M=Y8n%$Hg7B@JS#k^1(ms19WINM@Xi`v<|^m zssWUFwRzd@(`PvGo`HLgJY`M?cZ!}5)O@f_NDpU)Sbs=tu$?gnPK&@=@+oI3R3Y#F zZ{jC%C4V3CF82GJ!{vK}x<|ulbg5Sl2#~c+ba^hcC*uKGO+3-h08G7FG$_Q34B?kp zAWOqzME~bS=4m1T_Y}vr-5&W^h^x`;QU|1cAR*K_?CNENN&XuD^b9pX6< ze|%S=lm>$gZV=zSxDo+X=Td>h<)XyBw_Y|G6mkg6@GyzbQ|A0V*J`p*p&=_Titd0~ zio(i|uhCy!*@TeG%{WUvt={NHxldkdsyD^EmdB&*J|oxDmTd6IR5Y-y6lUnO)H}A= zMqQ?UCBJntCzc$yF%#crG{WR(rD;U&)6dGG5|P8Tq%%T}GFjEtTCbSxR8wf5k!>JSp^F+NsPsc8 zsoS$fHeYPtOgFaAtc!~w`AhQ=kK??A>y*e=qO=QaA)FlI*+iKnNJxUdwS1k0rO@T=yq$9fjhs0 z6gxYAFyTpwh6bZ4i3SFvf0U?yFxn$g-(d8(M2l?{dE|~XhT}S?#P;DsZE0WPJu3Mk zlFzZ@kR|priHeA+?CB$jF~|1R{+6!RpA)hTkG_1mgF@F#Lzv_*+o;*h9xuWT$t7=o z?tHJ206AAD7f;%)w62QhEA00TrI*F_Bb26!>G7^2F&bRmX18|aVSEs)gT;nK$vQm> z+y#jS4u%TM?BLpT*RGHU*xfE*gi#>U4Y{Bnm43G}koea7vxyF&ZRZmmhV+U29u%-R z3|yRuuO|#3%saW35dPNH(|ZU9FrM6i0_pMHM8#tNl_aTNSt6RAujQhBm8pdkGDfPh z-Yl?h8xAKy9d}EmCe~*@FM-H2!3};Yzya$^fI?>Ag%7_`H&WpqsnA-G?1g9?KD0Oh$vF?RkxkvXNA|;o zFv;Q^Tu_~U?DD_IpIBc1U3yAgXjw!Qov=p;0Jns4mOw4E4)_s6M1(+%o4*8#8#OG?n-!@G)gERg7T##5 zc|>NKFR&kL4K}w%{VE!@LHy35QRA)=z-@)dj?U(z48@4Dv2HUi& zJ}03AFh|3OK|e%nD1RD%LBn9gOuY`#=Np|i{@$Q}7wF%4)Z?^8D*VgXpnc(15d6)! zA4vqJnW-2>)pvL5b?zDk2F=tPYuq(F8(uF^f@?K1RzeT=Ta3-DkvD7>NJC@>eOq6n zt`l(2X=}38cvWzx6Osgzu0Qk33DCIj$W{a^x!)?i(Mv6?mP1BUL?WbJlbuF{wAM_V zYBkTitUN?CZNXsLNipk8)1?{DNx;ODg2NjfJG@cSvKu8nyiwAIH#)Zal|=PzZIrjw z&f7&N$h!Q8*rks8%W#E#ogUfScjT}X>YpF7Gno}2-yjRJ(9AG?SJ7rd0T;B{TNJ9^ zs$oU^6m=f1Pq+9&((;xpMA6Y*QloU~6=< z>;vF;EOFXjNv%}-aEDvacn|K;3dA=-5gHW9t}(opQ@$t}mrYVQbxze5v6yijrYG9O zT;VlNo7fOJJ}sizYLA=hjoqVYNe&$KiD~xAfd@)#zvmNF50Got@|RJhKy5q?wz~Cn zNm3KDiYimD*dfE45U<-jVsX^|;Poyu8tjX0%M>PR^I*r}5BE#S;=y~o{G0Y3x2kz8 zJoS@p86<&hlSQxm=0)|@OYtNXJt42$Ty|7N7i{l&uqfxt`<%bJ97l=bORaO#0I_R{ z0i_dqzlM$m_iVgXL$GHG(Toy$f0Zb*s+CGv@059qz+~ShvazA6K)e%IrasTO(87zS zCRL)HhqVC2zf_U0-MUX;#o8*ZA%T7PUr9Aj@w~s4rbBbDwf{H?F8 zATi!JsWSD8@2I~sr}<8~^vCg|CjU^AQFn1nbt)cB-!vU>EcpzVPRiSQBQ>c~Oej)! zV)^B39U8xy{sr8+6R9^t>)=OGVvETXSygf;xV}?V$@e%+PoYka!9fH}C}fM?!wHpZ zbPslX1E0slF}CA#%G6ASI~J9)czPrrNu%Rufk6Fw;fESbtxZQ!m- zcXaA+-yRrv!-`Sr`E_$5uzG|(iBP#wW%gen|EuRuY}lF4s5^+e3;7#P#*^13O0dl4 zdoNq^=Iuf@dO2ee@!QV`6G^C;cgwRIPvM*%@}UG4-ztA5OC7qcuAY~AJw>r1%N?Fc zL=cg{fXGtKtW1sGu0({B>QZi}WVssj{wRIVDs^5NHtJ9Lx%-Bp?0*~goY{}@bN3sD zvd??*b7p@#KXcmce1spy?j2Zu2=&Iw#NFHUvZ(q|j&;7mDY@`{wf4JinUG^`fq!p@ z`ZggqltVxrxdiG5#MA%c;`)KEH}Wm4A6W4&zWMb7jn#Yu#CHopr9=%dgzC?cU4A}C zcKP`n+4&hO=(1scLw1RO9ZWkAZlCm!Rzo~Fsqx5JGTR^V6JBzSIih*$&v`kHoL#r- z#X|Psk@EVb{qPzZunpapliiPEuOEe4wf4()o49tnF6ZCv*XJ(Uuh-Krjs>@MYcyZ) zhBd5+^#^kLFZ#g`2!y|ruW4PQ_n zUDrd|jI_mG*-$%}JNF{FyFZffT^?zTU21v7lCO1&W*AKOAA^<`V&f2Q7XTn%jlY)tLH{u8~v)_8L4kuKQiM2s%qPT~X&5*S z7$*K9Z4MhB!p_}6KR7a$eiXvm*jjNC@ziKcr%wzYQakMR7|%CJB?~OSNiDI5RW^we z`wllJQTSqGb@OkB@ld-mR||VZH@?<0;VuD6DC{i7ruw+j91%TvJ`>~suaJpn4_Y3d zmoceuaeER)=jl^4Y~->^{q@VLD`8NcM)>Q5$-!j8RG*kAohr8b&D20V8R9KfBmN;y z7*kmH>bbW}W~srbDz8pmovUX3%{lZJ5%Yv-A!~j4UdcH>laJrX`dXVc@!o$leE)mj z``+ot<1GQxgyc|1N?xIC|9dy4%~eROjhsgL;NBO#OFwTd)z3T2CciOdc*jNu`tww%u!5rL1s5=Glc;)nPuWI&25> zGx-4cvM4M`jT=H8JN~iW98p?a{n36kx{lBn0;A#s0j4N|I!j#9jNOBXKp{^&duPTT z**tt?_wWgvZ2E^HL2i!zHr4(%Rey7*1`;q`uvW1id4AAqp zfZipa@;g)9(#_L3uHqqN=V^8F;WvVam=0Kx9un$zAQptkg%UoLdnHr1=+>Y{`Vpxv zsNF`}L;AG&7w8)SNXYeUcFK+Bh#*XA-P`PxT`q>~@0JR|&rv3j0-O(oX?WoC2KdJ^(o_f~gaY|Z8&~at zw5SbyNRG#6Bn^MytW5YZrY8A#?$t=}!trN0FtEDpMO2RBHb-tc-J(M$t-x>EX#ouE zNxeZ+nf$K7$^YdSFR=f{%+>d-w^v|1JubMaK2O*<1;JG(90?Q~VRVietxgduwoj=j z3~u;`k`#9s?nG4&lU)qgw#dx6yWE*`_YAj!)wuFiVA-V1AqD#H3WAjcOI>9`5xbVy zWVd3IaLTJTn<@^>9WO^8VL@>3U4_n^l_hS)Mgynz`pZbXfdm|*uSbso0ag}dt(mj( z{UlCsD^}UW7sG!b@g@?-yA@k)BA5KVB;G~;$jkMGi4J4T*M?UA(84&*u>G?o+Q?iNKMCWqF*cptY0ZkH%O=4QJbFU zRA%ER+4wduem=i|_?B#b0`YXVfHm>nY*ldL zDI4$0#7|@^Jrh5kEly1QsExO0;+~RpTPE%)Q8#Ad588M`CT_*8EN7@G~Q|;dTjodfaUi_Vl|OCH$ZbHwcAx$j+1z;Jy~6YC+h@>3+%D#8$4Di5^ugf8VhzN^z=aoWw9$QDw9Q5jdeL?pJ?cd}ZS=So?XuAmUetqYQeL#jMti-epD)qP z63(|kj&?Nz;?PeG9?(t_lul|7ZFrw{&xQ|b-)#7(cFcy4Yp-nhgm%e>Q`#RJ?sbyS z4?&&sAShm`C_6&{yGWEBx$z&eBTdro$%nYi^{v_9sOwKPx9}J?oH?=Z#Rm5$O zT?G~i9vfW=KYdlg_mHmf4YNW(Fy^`9tv4H*L<>!v%_yxQ+KafT7uyt>3s#=Yd6>V_=OgMxt30Jv3pTR@!mjXC6>zSBVWVd^MCSI7$#v@)}<2y3({OoI%xCgC1n286nuVvyBY<$%P*LK?l z*LwQ}*M8>(&qCMGvvK}2lDgoT$>@Q3ptmY-Y#w@}&VRGEod2fj<40WW+Z}QaWIY7i z2j2(gV({5u9q>9Sy6W4ro`BA*r=ctB$>_^^N_w)Mm{VC# z&wW`>(!KxMGqF{Um>#aod$CR5i>(|(eJ?&Y^j>fj2|b%X3W4I|0i}Gb4vEm!lJ!8G z(+kW&5vRmRplZ!bFBBAEdXZoV(~Ch6Ox!}yy@{!UK4s4LZmEgwj2yewh@TG>jiItT zNERImbRaK{?}OlLo%e4zp*%*xuo8hX(+tF{W+0}C`02f%M~M;@U&naCSg}eZ+=^Y_ zBt49(#-*eNKm&Je)dZ)>CXJS)Z=aXsCy7s<#J_kIKiRlX<8ub%xf-9Hi3c@WK7?zI zeLh^%sqVFxCD>%7x+l2)l>?-6xS!^^QgUlL{2RAw5JB68QRr8hYDL0!2@=LfkT5=i zgt2i>eovk3_}ys*nq^ucA7VwCWm<9K=Hr8?!Z+6q6YI2$d1d`TfmjIjK_KvqEmi!I{Ho8-Gx8VGp(Xt~Vm2Z7-o z#tH1FLSD}A-sI&ZaFHJ8OOHdE^Y5L5Js$nK^Lw2CFZKA85Q5P460&<4OAuiR*1P># z#GsSc6C1W(9*av|8-l_Y2Oo&{eajd6h<{|~cYGlb(igS$3xWWusJd>Zv)hNAhezqP zYGgL!?tgWolw0AIE3@T(+xqO~(pt_>xz`Sr+xBfO_bn~gCgl)A5Y3}DEGIllSwN^>`=6Idae1UG0bW;&(VFkYK&Mxe{=MSYIN@wYth;)I@Us0V)`Lk&IqP(ya8<1RYX4ZpbfQ1iXj zdGSS8X91-$t8?n#U!9l!;(1o5z;^jEO227X=|}hV4`hmxw~(^refc0}wU9I$&a&s~ zS-C+jd{)4j&?Syyq80MOQK1eVz$UNaLn#d9Ai);x#FT@S>H~FRAg^E`*;fFJ zvP<{Nj%nvH<#eHz_R`=3_1Sysnt7=|KO}<hch`&U9^tSyi_!kE!^=BJ-v1@(eM;%{`O>y;mr6Fjf5`FZ>fOMr53H{v#tEDZ%rAl zuwlGg9xv}JBh#gI<(j}6cg`9gtlc}Gq%u53 z)wnlc->`O#Z&u_?ZId|@sR-5075w8trga>Tu?&6gxxEhZZUF z_nZBRWq>sRL0R;aS0u^@Z~^>!F?;$OoH5n~=tQIwbkFw^BNnORf7Je*G*J&eac`i9 ztv+|gI$s%W(*iZp;tl};A9kzLXewPlsDD`cwMgxTzPf3Nsr^jkL=ibXgp6Jo9hHaS z?=zK=Gc*>s%*^g{M@wTVX{fW%@N8Qt<>dx99cyn-pKSD&9mQ}HYb8#L2 zp2Rfq{yJZ+9x?@KlQu1@|GuQa4Cq4A;%Hq+Y3ok_UW{sHja$pgMg!m)jF+O+5NphC z%xmu>{#$OtQkHnw{rFzFqJ)?2=8)+k{4OfABz;O0B0m${6AgHCS}BwIQhmWfgY&5;)lOk>&&*t%#zbHR;gPtQnV&k@ ztod~sH{xwgXH4J1!~8aOBBJ@DTmO6%7L!MZ@s#OdC5XOVtpc%c^bYAFgc}P;Em$dsv;Bc!H6RHDVWU zei?d(kE%rib6}6>%%mUhMlX!CFMlb@-Y;B;K=^?hk90Al$g$;5N7@m=ZCaQ~ik}l7 zxCa&Q3s~eVDwi2Hrmkh-EfFmkX8~fGMAi&={N0cd! z!AEh7MsN&&gM9eW#4x)8%w)}r?&orMtGeutOF}MH#ga%bz3HXmj&p8xVX9_|@U!R> zj=Nxqu@GpyVE90^4pZ;pN3>8SksWF&>{yME8XZTiOE{bfHgG$vOQ=&y;pq>sBJn4w zBi02w^9ih;1ma!2VQ~c?KISx4a?7OtGFfW|@SyVPzM&?M*&o=YD4$;G3ny)>3mJmr z9CEM3VW-TORXqBLu+J9%LnZet@)csgw2qJ;74A!Tn=mKydrw zjZFK4^Ak7b!f!{?B6ZtcIf@@2b*mbA&p%?Yd3R?Y0>#guF%jOcJmWOS9)B~V@TbjK zlj3khO@xSV>NgvlT;LhoX?k`X5%dRV1k5MWT5{yJGr#7jVxw=P6`?tDIY55#yS#ou zF~6V)vuRCrETwy`qM6q!AuRlflfP?B>_Kw|Fo_BcX0a_|H?u$SDJY&-^(U6+CIa{t z$W!W5#~J8MAR1iulW}G;6PNi2zs~BHp6sU+%2iI$*3Dj9$5YpPZKY`Iy(ZQuZ5{t_ zwH2L!1_b)9?5u|p`72C|^Q$nsIW6X?&s;9F@7K&?3ydsR=RO$NK)EfT%1@}&A?=rl zZiniMVK@Bi^r2@b)T!zD@>2?5L711TOod6Ok?qQ*J%v70qO{yOQ$HXAF|{N2@==4E zE#WAwUf%ecZEUoW+r>i={xv({;nw-p?IsZu6=T1QdGn&)1>CL}9$Aq$;v+A_Dq`i_ z`j+-lYS1$E5L*7K)h*AUn4PF_-<DAVb*4#%z zVQUWucR{PDgz|b3EWZ>-BJA(xD_`B&Jv#h|`##@pNmu^IZCnN|V*eU`1gG@8 zoD~1qHmxRp*UOP)`kTURt5=G9!f4MWk+xd=<;?}jYE@e{NmX+?BR6*IJ1040O-NQ) z&-6OlOE0W2GV4bCR3>stJ>hgPT5b?|>zYXWvR7(re;t__v>h&u$sCJ1;d1Hgb9A(UqPTo2 z)UrKPGB{z~Gyb)qerlvJ@4fL+4MUvNI5D&po)#O}R1Ugs) zjTQ+`7aQ#(TSg(<)ewSoC4RYTu%)u%-6LX`#h3bW>hiC`w5n`mG#RkIpn)l9!5Em7SyYNDt)$S&?M#aJ9RRUJU423$2qif^bX(6N6i-5 zOMJI{)IC0m6bCXXQcM8iXMe;0YyvsaT3Dy%T%^ zA~w@7s}ECBxUuD70(QcE)hn0)B+_iUoNp{fe5PoAH4WVviyJR( zT$~kJai3Z81kTbY@O|zqp1|weS=@DR5AIx^%SP2_r&V9`f<)jKa%jBWc}DpcoG`A! z+#21Hc=Yns$ew)K!r;BK7j@tEvvXrTo{@_jF&YpuA=^|HY(zL*+@ztQB1nl9F8zv?hi5 zP32kMHe3^&e*Y^bLvc7JKu@c}J$IWZbONqu5odsfLbS$|p=>`j7trfQ?gR*M;dJ6Q zCOYtTx|Yb#3Aa6$z#OVhZ+|Wpno7uP+u0bi-G2fSLM{;afxWeE?4(B30pRXkTQSf* z#+xkb4?5q&{sI>J+s}zr=7ERzElLuwY=%jXGVANA26z;@M|pK9hoU-%kox5n6cw)` zYk+((BaEE?a-TQ^p*L%*1~7N?8k1goBa?G#I=gyZJBe#w96vX*wxNu^#nF;o&v^r< z+uty+s;cVrNe^X)!npRT+;z#^hjNqaDh6IJT*$Qy-x1jnv=4lroyK*eh6;j|N6_?& zoM)9+Wobl(Pu1^mSbh_@-Opa3rWefqa2vmdJ4`236SqRBlEorNGUL;^Ow^~DZ#;>h z6yvlX`J?klB-V!wX4bs}J1Unzocgrc&yPn^PUq@J7r!w0^X80dULd}Ipq%rKS|0HZ zB*3RR3gJ(B^gWaQ{_3_V)qTrerS@*0v#m%hziy1Q{f70i&S)en_{k_-*G(NnDlVzV}vMR6sw=S&O&M8KmccpuV@)l&o|<9lCR*;-Qm% zrKa&t|2>iaOU=?5c?R=WD+qSKGxBuZC~Ptld<&1QC=)}$7u|hNUK-H3nGbP?D+Jp? zA_dD8!jW{IrvDbP3%`Qn4JF&YZoGHe;yrR8gU$h5hX&tCg1Rl^5~KZN+<%w-(rj@mo=sCw!xvDl^h_WaQ>ZUCrvl+ z80-9|JH%Lfq{Z$ds@~RqXU4AHj;Uai^bS#585OH6&R4OlhyX0l`g<6w4Ei0sZH$~J z?=w04E`z>*BO~_q{!54NeIq~H?cX4O0CR2|y3gjU?s2XRnLBzxNAL9SlD-hioPno3 z6aj)GmIadB%-%6*slyVUEF=^NzvvUQEa^Ic1DNkHNc1W+P5&jJLdBrYFkMy0JDh<7GW` zcx?ELfT&_B`nw}|L1H6$y3wOL=`)q?jF%lu{or==sAL@KO}5?e8r%y2l~b`# zFw7A6&f{{`|GYI@N7(!Z75*9 ztit`~A&vX0MyCT>O1Hn2xe^5wU=fypDUNe%c^>cf-4lPp5$GYeGPUQm*oN|zZC=#a zhOHQ?#=H&sj!&{qP#$_yj}ZbA1~KM^OT4cb;;KCDZv8D{xqfar08#kLGM>xubj)Y_ z*u=@RJ}OKEuEv@v#0f!9rkC=Q`B@hSoZI%x)>!yngvukGvD}U`s~=kK>*((;1$Zdq zK$IjO$DQkI=omGO6fB+%%W5kz>uFn!t;9~5N4^9YdM7(T_nxfF${p4Vif-6r%nwaU z)!yLJs4JtMo1=EIIK;UV3d&DMx|c% z32#3#=#e9^SIAH+Q{VXmX1!bo#1gk4*zbz>`)VIR(dp)mgYfwLTL$5Ao=2`ZKgPq{ za{dO~@{n7e@0J(1<%Mo}ky~EumQQXiyWuTDGAMihOZ9V8NI$m(^i#U_h4PuxkjUdx zw(kWJtGxa4OZdzv%aho(k1x&VQ@-6Nu?6*4UC!s$pcWrL;wJe_u%C(cQz9Q>g$;kN zW?)AWEd}F85fW|zX3;c|GXG@lT)?9`ssNnLZo)zrc3YyRZK`OgqKk@#Dj2Ha5eTKU zp%}nNpuQ063pLwTO@O#Wvc23EwJ0jss#W`GRn($U+pUr;bjuvO}#3yU1LhXr4qLBP+EZ5za@ z$Kr8Ixp28`obyyh^9CqMU~%Tm6ki{f=jzh^;+>EF?qE34ii_&8|T_{=DscDCtK>J9WW|v zCY|f1147n)q7%8r-Ajg)sHb^OnpC&%%JV` z`M(jh*AHDUT#)r_V-vEp zcRt-3j^)v>bYuyAz4eXGy_~V{m)DQxf9Tc~_S~te@#PV#PFW$8MIP<9dSQrQhgQP- z&_!Glic~&q&w&nlVTFdZ`%e-Dvr!JPlD-efqu(7OQEeRBZRVa&SfNKa;KxKo^17>J zN^FEF;>H+yb}Lre3%#7vXZo}VZut$|UZ0^0j z$@-$QMi+`(X}UYb%~sYt;g8;If2N;T9g*5?J#H3`;vxUE`I{LwZ?p+2!~ z&->TMCgF&!^>2v5@047q-H4LvW_|3uTk5L0nYtn2vt2OPTKZ7%cNj%J+C7); zFMD_UcHU*V*%Y|Sc8am>wC8aSIz!J`l@C$o6j3ImWuP3z-OMgx9uX!bLM(~g=`Q1q z2R^Iz;qZ|AQy%woJ^5A)uB_MD3LtJ?YfOvfo%^+KFJctEo3N#V{~ z77NaoDpz)|#y=vu#43_iFANRAo`_&kZ1dO)=b+UQP6hgK_%E&w-q>NK{u8fq(#rM+7aV&2-DICk=a4getS+zTqV-bTfX^v%!axAyK zA7Nl{(YoNukBnkhlvn8pF1mwocZ_D1VY>PE7fvHr$C;l)<8yI)~X5u?@9Fcodiww#Jz( z%6`M5?9X6PKC||6EQ+U7Cb$;(lZ8UB8LKC8_=VNDI=6)W#KTeqQM7+mM zB#UxnInKJ@0@xRmur)P>}qfzA6mZA4m@KXTMl&+HD@dhpyzFm84Fd z`ItTcLO{L0AnaM(pXPpswd^p!P&9C?1|c(p&)gpQnpBa@ou)59*XROI3W>cv zdFE9ap=tUF=!^5O2KP0WrKFpWrqJD9)~h05eSm(9z~#;b-2hAAoTugWxE>np_|TC} zG+so2(dbf{0{reH2u0)px!TI*WTJM!`lKh4D?-hhlqVxAZ_hO=T*il@<&&M!wS8kx)rZ(k3}derhs!DK{%14mQR63>_B(VCLV zUjNoNJK~?%zp!uAIBt~w*u>f8k@~my%j9QNfkf)(sBe0tz5qvf@6_wm_?a(KKMlXV z-$G# zjrS*Z-J;3gpPk$!itm}JZc~fsiSimxPi|-2y4zbfsAIVR+(S>6aPNGNUObxWnMRxp z(QAlf?n_4>y=Xk7$j2+>Y%8k2A{dF(&%zzqHB~|umqzR^n)S;gxeS3e>_+5T2jLsB zqi~!MGgK;;p@amyRoI@dR1EErej3^%os>MnnX>6d22VQrs^wb$rm$eS!(kh!|!g6)W?C9PK#_I0Z1+~XssC^j_%Yj zPS9_`oRyeLu+VBN`&(wlk~p%RxL(&eGPkZ@>Z?iiorvrzCx6KadS$z~8pVoO@^NMZ z>zukHd!(C^-zTIo>c;<_ffW9)jrdC?{$9zUv}Ya28<-^FkEPOx`Sr9%xlDDx&o8hw z2>xx4qv}c_&dX$=h>AMJ^;#?yyq;v70WFeX68bG(d`s z{Bb3Oq*owTIPAN;;U7v0kG(O4B!yEk7D@wS-NodOJ@6>1E?e8TPFl@S6ctZ`X+FuF zA9v+&i`Vorlw;XKUr>&0`XX4U&qAW-MIFhq=J!Z;~gfkH<7pCr>Kg_PvlJ@Lt@tgfhn&X_sO&aMW zy});}jqE^zt3UojNz*M4+y9GtI!!$Vrk=!h$!qHBDbTMIX5yKee|z#!;;aF0ZphQw zA=79AWC)FQOjN+ABfdw6gU-Y8??@a-H??ZILeg2f@?@Y9WH+WrKa~ge-Z4=v8pY&Y zpn-Hv5a%smqiOD2f;oI>Vkb&sZo-SxOL ztIKRoy1Jw3>SDvyO#n+;Az#-#gBnZup72?3;_5`}7yvSg1#FKut_`xx`V*rw>EIb4 zFC!atGKGHXXzi?jSWvkS-sgqRyq4XB^)RA}{B&R|SudRIP84}{v^Z#2uh+r3<4u}y zR+qX9GLieY{{BLGUHN4$0oL|XNxNB>sO*tJ;Je2J#*djHF#%W<89lxXv>YVQs?m8s z)JXqLU~uXGo)_(g>5P*m(J}EML0ZwhuoZvT zM$M7M5CX) zIoTn-W6EjKast_bjT%^xo%h_B(vo9JJEIv3vjYPPTTyo2Go$h*4tKPeWk}ooTYi6& zILPmQs3enV(tggWpkBb0+%4(cZT#+&+}VpUVXfIY0ZntB$6o|)>SJfQU4~u+21@6;K^eNMh|x6(_dOJ0CKJoE{R}*v<=dX* z6LEO)a{cX9nw4pRE06YzUBV1Krkst|SkTberD_`OnN98ama;(EY|g=KHs|2KWpluT zVzEiEG8&s>@!)U+F$Y_tBF_%b$-01Smr19`Yo>ktItk5S19@DB)-6_qw2(fiX z3|;+D;(zUxCAPOCZwDBI&#O0!3BL}Xkw%%0oe9oi0QaF1`3}8)=~LPC8a_}S2aI$c zQ*{S~n+8m7#>IftSyYCTOpMdKj=c3UvAuOvp&d`0(<$qbe~SSoR5K#8!?Gs~pEF_b zO>={LlpDlCpX^A|ed`pjgWK79W)<|n_8pg$=-G*z66G7dF#eO1ouG%e%VQG4hj|PR zr5rg{^t|bXvC{96a54-&<#LLsaVboM>`GJK>bx`lrCt6x|^t4@}PV4bWG{}T4mo0-iMDG=n~ zkcr2^ZFN4ah$dS3zjI>Epr(_GPCgs|nYR0X z0_E{ED2*eaghuMo&_^eFhcvN=&lp%VG~5j=QNMi`?#_7e`Odt6>{~YP5e)K?masKH zo36oWEHQ!$c#O7_rxUG=Z>RotA+wYFxcW$SEB4%CAD-R+ zFVwJBt0gnMCpXcSXtSD4*sqio&4CAvznp%_9&2&UU^csAr1a^M7piYCr8q72Z@w0O zf&FTmvn4h;+5p>I^OZ!sh-~K@KH_9kqAlE9Zp66Zi(aGW+DvE!F;u+T@)WCH)kNoT4(9Ez^j<4wR8u;voh6e?pUpaMRi>jYT^v#F=lT|X9(KHo zBK{S%-L!i&ht?8tb}U^ZvnYc#E&lEJ;lm@6fV@@Yc5pqBt$nYIx)WgNpf%H$0f(c& zRu=7WV!N~qQxmq_aD(}h{taS#wW&Q*zO0N_rWeL*ZdO1kFMhq5A!C`Zj9BIsgHf%$ zt>%l)@<8YaV}@HpbRYJ69Xy{6barOaQsTGa!O~h9Tk6c3^6i=((g7z} zGbyoM>&n|CW%$gOFvA&)pu08QfN@Zt-ixGRfww~fW}3$wtlh=>k|ohHHO&p{y5=c$ zNbq2U;PiqVPBA+?NXEL2UO7U5^J(|jzt$z(pa58qs4vnkeMI2W0TM!9G|iD0&ElKx z2jWP#%}JLIp`S84lPU3j8Ez+k8-L2+FTb-R(UdsEf0fizpRT8xiZt14-P=ccoSqty zk~uxq)|pqR(gTqGW}Tp} zlHR_CbITWp2d~ z3}EQ39I%xcVyHZOm}Pd$S16ec!Y!KA9CgK?jocGg#TA$!Xm3;=_NUj?LBOUvW3%qHZLLL8x5##T@l*ON{KFAX1{ z0y$Bt`MIHv31*S>jR-6HslwrTlhWbPsC;XgfF9BTtf6|UVb}_`rka{x_6(W}?wB^d zBLFiifj4$B0<#dZCC;!yMEmwJ60tNF>`|H`88o$Dr;j62`#Zd5CtG?0hqs$PomU=i zNtH%42$jqdaZ}(`dXGdt5rQb-9iGINnxfHkxL=pm-6;WQ&X`#6MQjJLoIz~ALsRV} zRp<5`i7)Hu+&)8F^6oKN7iiX1n&olLQlZk&3SpLii_mj_XI_p7rn%`fY*b>~ zI9n*|au`d1btcYJMEsV)xi5bBi`>_NTG?C1t(j0)b_xJL*p>!GXV1kgx{B55|aWJNZXp9v{+d4Py$OrC_Yn z*zz&4g&MnFV;_;&E$halnWp{ILb&#-_OJkzjI-=$7oX{vDBTM{undjj>H#FDkSWgj zn=@mw8Q_wD`XDWu1czc*3{QtbN_2{uhv|-eCl5m>zhQNJQ2Gp1#1GNz!zO6I1|?4( zJPChc3TV-w4odw_juPa$pBV9chn{ro*1j$sCPpqP3`6O#9aRkgKz=;~VM(pura2qZ zNN>x|^LEX%704vdX(!Jn&2vv?ZEd4#(*?Y0n>66hoXC-Dz2;gcHT{+bA$rZu@tEd# zptC+l5!RV^hZIf5JG7!%_{@x#XFu2hBB=F{5X>rtiW7*e()71#hfcthCP*wdw$<+SzHyuZgM*O|k(RCPW!ARS)^^%Y`|}Tt!(L+eqj(-R_|K+61RLCXS=A zEnNT^m+%L1k^7;HxYNUNxOCASiAxU0i3fYTCihd8S?(f{Im zzxp=oLICR^)3B~AxNFosN8K_LLlzIt(Xatc`;fW|G=7u1do^6=K*mI=hE3P_ht*xG z?#=2hSGP__4=&Jh!F0~+|4x~tVq2=2G5TSLmuB_6~};0_IJRQEmVCIt5? zb!$jjD)As*wTF(^o$Tg9Vdi+?UPt`9GiCXG_l*zB71Y70HO|gjtw?jWwL=6yyM!IU zj&$KAK8dPmV!o&2h5#|^c057ms+Pq3K*tRYKN0sKWje^YO}$4F^SvE;$=%|9DzU|* zTxyqk&RS~;cKznCUhKh`};fywtw#A(;>kXqM8CFFM#q%(G=)OMI1^gcf-Qti3E zie&8)z3xcj%=f996qd{<_LSb4ktFkdFL(Ez)Qd{Z);9|I2Ad)n{>l$W-_O@vTl^ST zIC<4D&Ur;E&&dzEK3^o6^f#RH*1U+_`CJ^eeUba5n23q#mupS2ohB?@+Q==)*<}H& zD?d{`X}&#wr|22EK3?)n$hD-t{nL5BR#Os9k*Z$qz|jzR0R@cfkdVJqPas5E05FXyTU#1>ubNZof^I&?X9k|4stO%vH1;+ z_)M>RGGZ+J=?UOI)ik{DOAV!YD7ja2g@wTP%9bEkwa zxNGjWs(OpD;y=4Kwc$-%I~3JudB2nvmE5PbztqC&M2wbMn`cOYB}XXg$fC&dDJ8Y3 znj>Uyr#h|vwDw z`S4=|3IvZ==|yEPQEiE;UT_jKMYd36d}(i@>Re}DQZ7v7lMYFQTu|(OUti+d*6Ule z`SjZ#gy847!hd~V--&CFU4NwH%O?CuH6@w}VlVRu^A3ym-&lm<2)%HAr`Zvd`9}7E zD*UE_@FV*>E`qf5?tS>~3=MbM_Me}Il7h*()L0%pi;R{^qYxGx>ZwWH~sbTAttP3O}{C@`6B zDlwXvU6}U$1i#%bDEqSRF=&bpktiQ2?`D#rAn}5qjfkH_DBQc5J zpeNfD>p;+EV&bQCwN{kirBQ1N6Kjgb=<_S{GPMyf;#X<&##b^R>-yDst-O?t-gM>? zZhtr`#{SUm?ITKboM!9mlP67;a^+c+9z@=NY6>&EMwWSyZoHHSWWgiD?|au;zFfN$ zJs;(R@?N=j_2u5*%?#I0k*nYVW2HTDw)j|Q-n3td40sm5T%qR@5e|2hGYh^5y!ln7 z3*iG^G!dZt6iY`vlR(dJl|mU#{QVZ0c-4Tun&~ssUMHq93oXn+@&-yD*NZ0d`T3aT zLoW&rRrRO7F5^@88QcWlh6<0Mc#H*;6rme zt2#PF*Gx`ay0c3dsCfhF1ZP~KGs6k!NR2m<1b3Eo#3zVunv+C1Sv}!>0h7Swlb8Xy zG7<)P7EpxfnpDX%H3bGm7D!oLKeS<$Y5F8o8)9q_O#y1i;2N=+yR;A$lD6+wt1tKh zCHVKc+z0ijoFwgK@y@EJI+i}A&<{ulK4S`|7AZSdCW8U?P>?0VFD~L#5)w8t4C5w1 zC|!m~XF>)^9)V`a4zyPt;kBLnY174PdC+I7NSrmDokXK*s_fUq?(iuyhdD=7IX?tvi>>z4j(8ptx_8#rA=iEHs_Fc;> zQn{aO-t+tSzStc~Iy&QPld%h4S0#F4Dh3HsPfAWxj{^l1r;5x|JZqQ?k@d`Aj7^ui zb5J3%7_gz}GxCa4bhH%Bw|ErU%pxboAViPRMXxJ#&YoK;DBkC8;^mIw@J;TeaaWll zP*HdFD1{DV^@~rbZ};CPHXIrFXeV<=O~2@K8R}Dw)8pjX!vHf^XH}}REER_qM5RX= zy=?K$qDWNpjN?^Lz`buCiZ>SdvQoFj)3oDCT#aa~Z%yZ+NeQirHa#a!{m(lfcm%ijOfO-k5&>b_KH&kG;^E21vIo z@$odZE+#Lx(XFx8RX$kqbWJs z?e+?}fg-Od>56_K;)8bYE<<0iWf!JSjc^*2?_F-01xI^i& zRjEYjfP4oMIeZG?8O7(}t*FQ*Pf**$gy%lOOf@frKO5krs(Kze=6FFEVknvGNO9jc zmI;dhK%8|h@TS9gPu9`e5lc|OH|8@{J-vpJsy%2*C{CBaVxGurkgZ7GHvQeougnUY z`1a&7(|f)_1$-+9s3mHJrsJdMjF-EWZ9pAm#cnkr z_}kcTcXM*BKxF zC+7|F+%;04B3Zls5_B<=b`5a%XkaiMH5`12;GCiCV1hgv57iWL=+ z`d&Qg=mmKrBVvX@d+`v@!SdnBmdUC96OvBWvt@~0RLlXAR*#!s0}ABv(Y&!_y;HNA z!WS`Z|HNFykhh4{)?|CbB~)^`|L{NH7fH)l{Jz`Xlo^J9Gk)W00IdwoZ-b=#o*+nl zl{MLYlsW~Uyk2%?R;Lvhj6R!%QTGACCUKzaMV>5dW=36bs|iEF-iBoc7hsP#4gmxO z{}z9*^;`yjnprUS3+`dG3f}Hc+%Twg0QNaXl)*#2zfXATjYl^zrN{?>4 zU_@UH^f+NO_R{nStTK*djk0zLuI#0of(IE;5!#M#yR^%;a|WgU(}WQD#DG9!CnX*& zt$V}~JRZDgDWZxYMD3k;c}gf>DqLW1ikH(!%E9N!l|v-vg>eawJ6`Td6y-Bhm)KH# z%|0`(3@{~!Yo}YsO|J!yr1ei3zwK$DB#O~Gv^9SgTF@~ie55X8+qI7{atVVABvrhkp!nH}dTimG#H8@|CNR|xxx86?xHy#dm z#_c^s!b4jZ&7$(ccVIrzZ2jAJCGUELBW1fBzq1m~xOQN6ZD7N#yjYd@y(`Rk;k`2I z_<}Gh?ml=hi;9=Q@_2i{~b;DLGj4EH7ObvGt%V(aztr+A#2A z>jP!1`KHaRs7KS=3TAJ~zz$mRqDwr%tpBFL5;<~x_)1;*O^jLpS^F>3+vQ74Z%1GL zf93(oyqDXbfWf*81K_UK$I{&pXmsf|91ir}eN)}jJq>6#hz5@|<`RqwjfQ1LRet7v z|6cFr)=$5j?VU;z{XcJwb-Tl-+{d5o`zzu}N2XZSbZ>0x9dqsoU9G85n0`Lytu908 zIGkWOCu%%GF9QN&6aAE!8^ElRywlDfPMogJ)RO0fk8R(byc1raHv6~AL#%uA$%v|phO#Td zr`{H+lsDb}&+8?#k&DkVFZ*wBh@z-eO$eF*JZvk-z@u1lY@lih&yi?e)h1 z88yDTVZFm;^s{1!Vf05u6^ML-4O+;Xyx)1Y{&(^#U%E_c z(LZxevP1J#M5O92T=Ymk=Ns#6Ya?&}>|oDb-l9FNK|#`33ryHxmP63e2k>IH~sWWE)%oB9 zn=~_b=~8tJ9>m4;-5URcl<%s3X}onFQ})&F!$<*6TSzM6$bk^FBL|N6yhH;eh>N)C zz+4JG$PUdeQ~QO%CRG%eROur;kEn9^gD8!D7A|{>J>QM38@zT=7+DcYpmAFv0Qx-M zQuIBEutWkppN}BiA7_P9Mie-F={7;hj^x>I9hPcHmoqBSk24cJEL;8jQ7Jw@lH#)) z6Yi|o>JOx2R!0?sy)mDgXIHt|oXU|l@f?W_! z1sWO(My;R8$`(? zjk9vZ`OywnB!nF624!Ci0jxGkIw(XS0vzkPgeMHD6IEw8%(eRCN73l^OqYrelS*Uy z#hD=sSsBc6a3f^g6*%per=)HuoRuhc=#3oBaW-FO)3x zaf8<}to&>)sMN|5m1pDxK7P_oB{lL=#Y^3H{$>$iFJ=h z3Q); zrdfm?B#a-OV6JgLEwc8{LtgE$+y{j?Peww$C4K(QABDe`Ij4Jow>VV69Mgs)UyOQTD3J3eo$VM~bSZJ9Ff}Xz?)ImBU+o_X^>yrdBomOMOQhUqb#&wLPDIvElcD zo^i%B&zf-qy!^|B7YkiGbhmGLMe@GMstrd}+{g@4(u>Xw?AUol!C*9bhZM1Y7$g|} z6{reACYpRP@L0V-#0L8<)@__dBX(uLy$&(8kt<`ciZyI`dXvD>;W-gGeu2X0Q99Z^ zx}fv}nGiqqA_K89CYcexb|QxL(`?Pjl#hu{+J{k&ChF8!Qp*}qLxq|?W45RY={AZt zHuz+v*l+2Akuv=9-$yuQiwyCj{c1l)%o#i-KWDJ|HG$VB>^lDr_b{Bv?PNl23+A^( zxlvUi%!X^@yR3z!&1Hv#$cH1W6?0(!YNL@#c$i1c3LpBAwa_c;Ym*>;r;dq&^nNP} z>u~d25)h3!jlWw>-JkGC3LhpJ;0}I-vOd|`Zx9XO*20+)ESl7dS>W3%s3tk*?Q(Y_ zNvATPVR6dh7*o61s!Eq%l0s)pGxsEx)2r~=kJ3Kj%L=i1Rz$7Aeohi?IfsZdFCGPd z0MP3ee!07wPwn+seH&->Q&&%6-GwAU)neU_TE?S~CeH$K(YgzNmGCPZu8r_{}O9kMEg!lZITUXefIMrOZ-}lg`6?7&lrg zISETXF`2Dh?QSg8ux?hr%4C}YJgBBFX|6F%U1pjZV~CTAww7Gn;AOaU7wQhAS94Xr zsJ=aPC0tfX^G32+w^DNpxBFYAniW(d)?N2=C{))^a&{gsanYCUU^axdnz{{hwCYKs z#Bs-fW7^a6p=J<-S%MABAQMo7&wUxdJ%lcpDb>rYg)^|6S=XPGj5nex@TR36DFU{% zd0|m0D)QXNdS>8z?X85Xahiwx+^Fk%oy1_avS+eMidG>>n)fT0VwlYa2U<>l58XB0 zE_FoI`6ZhVImd_VmX5DIC&^43LJRNoA^)uqxV;Q`#?WSXA}97vS4DCf zam)cGV4bLvsz?^xE`4$u?Pdb$s@$Gwl5+4i32o4V#AZ0E?a^EAQYG}^SU#${g9(CJ z$Ve4DPBgmBgMjyY!*DJxiTQW#yZQR#)`>`EhaES zl{Ya!|MGy0&C@wn2S={e72(>Joa&qJ%vpC0dC{7ee6BB@`@RZj@hJ-fsAT~bn8pf; z{^TDo4cTRnRIJ`K888vQ%3uKzVHj<0X-W0@&wjWsSvLhAiUgm)G`Vo*?pc(CKv#}>5l(5JA>wj0vHH{~n)o4k9GX~29&3e{JzLqCp}Rx_ zFeqYrx*e^vNJ7wRiDop+UYv`alEL{>+dfGJZvJA`MyZvve5;Lm*`sqyms$OwDQXkZwM;9H$mC zQ<2jLb{FJ*FY@fsJI<+Sq>^6PmUu}TE9>bxB0Jt zh5phjDp_0f;5_9Q(@lF5v5OPJ7bjtDMQ#}NtO;LyuGUk0tY-xlD_DLp4;5@dl!$cX zL$QumX}-Ka&Nikl#a-}@5%eM7^6VwK$DdWq7>a$D zwGS)LqVSM9^J#n?*``rsn2T4 zx{X?Y%wNA%B{(}sE`2u(pU7`!@D(UO#`j)7!sGGHWeqYj^-SJ$>W<>*rv5uv_Vbd2 zM9LagCV!8p3z|Sl^2%hSo9C3{JVT+ak+Myku*-TJg}dBlZX09ma%aVzId<8W3RN(O z>D5>L6?p40ezf~^#u&OJIWds?l`Ns1t9dqTB zVI2=1jp*rG^;{IInjHt^y2Gq)j|}PsW7NgH#9F#_P2|?{^s4mD@##%Y1GQROL}cMC z^fpHp&ZK`M3un;zce<8|`100L@P^Kf3jbbOv~opq_Y1me3f^YZf;ExVm-FTOPV&k7}2WGwi7w%9R@KIGN37L1w1kHwvBE;()JEnAMDDV zcELQWDHt;dVU4E+lspW3u7LiJ=Z8VxpfAozi=1-28^g8R+$~g7YRWAs+gkGjL75dx zgZmK&qGFV9(;n(-Hgz;h1*VDH)8*gu3MzJ|N-oy?KC+?QY94O%E1go{qleF!u5!XI zV?TDKQH)tVrEV}<#kUauTlog+28ExkMscQayrGGl2q3Afz8bN2b%9cO^*h(BRz>|o zYN6FG^HwBpP`1@WqzvWj^gft7+%>RVn?AKgQNlx%24ZdYK7=n;}!AyvS2`RF$ zlqpEp&d9>@WlU7bU!A=)v^+VJx9D^l(2_hoU5uO!kuSTN@9Em(8>ziAz{uUajo|d& z<;AzJi&4+ABRetaA4}Ob6aNEhF(8tcB&n ziNQTn-rd(#tUIhVo&8&8P1-Xd?;4S1ctJ5AJ@m1r-lZMrj{-{qgp4b<^>l)pRq zOY-*ykiLY!m-4rozZ(9&$zRTdG5=h-6WkL#dE(61fN|dOS@QGl({FU;@XbD-8(Qyk zEco66)nqL0k6!~OS2H3RH0+sr|2AsS_!Jhk3!YrAu=vuj$bF*-!>ODZU!dA_FtKjlO|>lFi2(Ta%M-L#BCBcGiS;bzaL3L~ElBtMs~J+xGo zK1SRWsx%vbl8SXx;2>5eJ9{n-DK$6GpOd3zz)6rn*7Hk~C%(<@ZvJ$}?HX;`yVmG_ zMcpIkr<|g(3SJ#c=5c12CmZOS_(AP=Bb#hQa;%E1iJ^(%uE4~cGMI^^r>e4zfeo3=hVERV}jlQ;IEf+L+5P3Id2c>3KPEY z#tko`GtgF#QOE*)cX1dYPVl*KZ9z`xszwyM|6c9N8)9odzL0}& zM;H7}x`8aesarmC9f4GMD6e*%?K`iA>ifFaaDMNU#<=BVPwWxI*4Vzqw$By_#KJiW z_laaY*1p8{sTz4FH;|aB(it`1(h2E&Yc%5+`Vjr=NL-~?WOo?~$nA}g4^iyZV$a{R zWUYB)v$iCKlprOSfx0o5Db`)vjNL5%69>eC_!F@m;pp>dLxZ#O6u0(FAjH1;^bR&m z#nIv+xeOeTtI{)=&8%Lhe-Y}6HNBMBvRtq{7dKnP<0)5J0B!Q8gi^#+do?!smb;rV z$%ln?H;V8FF}tpP=58)NrU7fxA!F?gE?*&?SfriU*uqb+EPy=JP3QVbhgHl^NY4so zRO&_ReX!|6y`p#}P0j(kp;zrtfKIsp+=StVabmc^z4~43y}^X4;{J_CWlb9<*Y&$x zx+Rtm{TXu}PmG!We^~@`|5dS9+IJCxU1?z;pi=e>DuQFjI(zm;PTC6Q)%8C>%9>u= zx6Nu^;cl~Melfxx0Mq9e#)V!K^z1ozKLv^MZ@0%5ch8#{@7BycUa|!}+Xcl6#aib26cWX~Y)(6N1&ihnk(C0^lQA}wtLdb;gA`59^XXE~5`^VG z_h34JGFr7jpM>;F5<=7+8=Bx^-NbOOzy4-53Ma>wGWm$L=9G0+@PwLWRGXc@WB&`Y z%(j*@fTD7_q+a0(K5re!NN`{{!Az4tUKR%TfhUs)AEv}fL~2c^*G_iq!|cb+#Zlym zRdN)+BU*m_fyiWxz>C~gy)kUTW3!rB=cZ#a9Pc~I@9oLouVTybDKF+el5IHsd(X2= zPbHtkE%odj(l!3acrmvh-VaR;5)L>ezoV0XXD@PLbRW^kb?+D)8i8=Hyr2L_pg@+t z(jdI_hqd@#dkH+9`**=6*5|Jl?*rc8K7>rO(RTA|I_sD@>b^#AA3Ehd z6Ces~dd}*zwe~8Av~0kA91u+9!+;pzA|AbL|8>r`^~U$VN+&=d9tfv^cbB<-hwFO| zSjR$^hMxBt>HGd- zbjZ$hf?ywsa^U}s|9{;AX6(*(K<1nsK<5MW zzw3>X6aKAlVLHfc_gMOq$2Iy`Bmkw!G908`w&&V(Go^(}Wb@dsi0JjWWBBC-GFp`^ z1w$KNuXbT-N9Pg@kxw(ZoJ_j&311it-8O>yK*{k9r6Qk1zDzl=X~_YpKR_8^ftJ?%Mhn*UU~0zsGHF(%~o)r5$Wh$2Tv!$E7WcY}xT%NMjR?Um zLFUlBXn`I^J?GyUcN&XhO4=ExaLeBJgb;Kz@?`PuNtrI^@(tA+C!p zTE7e?L}V;0lQ-rG)H9KBEa4lzd zQf@EzFPGyW-}gf*%!P-$+8o?`;K;C$rtZ9%F%jlR?iWZo0*lFQU1_`ucpUSWGSmK>?R)_F;YGk`HoKI3iQMt5t;(a<ZBQe+Y zDHyZhHISYQ!^&r$e{ZEsb#B}Xis424x)Ex@5&mc)`<`0|LqD;WPE!L5atpgqs{WiJ zl}UuErW}zsCJQBEx*dYx2iw}eoUusU+{T(shDE_Abjc3^!~s%Ls>Zr^17Sl z3eg!LrECgZB;{SGc{JPpy1Z{Xb`yP%S($C_=sb1SoR??LNj=WLcWGeLUvoF{!1-Bs z^iEYRwlZ0v zFDOdajIl2n$eLfh*!}vM7XPz!@t>!7<^qsiA9Zf_oE{#ck3R1V>d&sX`e3wp4Vv5| zVU^g>vG&VzjW1J<^Y*%TELUXKS~2V7Y0&jnZ-!;Bw;GhS-lj&@+f;j1?^;;nf3^)%MjA>KRmJf><8S}9m%&{ec zZ%j5y6e?O9QenKO6#K)xJlW;PRZ1uW%D+-Ar4)!+N8(1*V6v971R(C$5p(NX! zdwtLO-TVFw`uq8W?%jKTf6nj!`JHoq=XVZz7T%@!eY(b`<;WZBwl@%hLni#9FnE{h zj=wo$)|)H-_F_Et@%Y>J_}e+W;UD0o$rrqxjK@A_#sX_7)$(e^IRD#m*gh(lP3Gf;`{HZiKf~G3cUmz#L9WOB&Ucq5N^0x?VTC+lN0-_Ep zeCW_f=xMVG(UGD!pz)^&<_L8=TUzYJCp5j_+=|}x&{O#3GhN793p0me(%1o}pSots zs7MJ4Cr=4KBW;eo^Z~gezPI5ULrj`q+_wC8>5^P1h6`8QXe3PilN5ObtCtZS+#`4x z;KZJ!5^qbV_E3~(NSMHz+cfS+p_0iETzlmAWAx5Ft(R77%LW0>2Zq?&G z2k}(*p1cf?z$LPaUOnbF4!6YOqwA1hvF-5G4SWN=Axo5N-WGJr8BCN>51sABTZQwd z;9tpg12sb~F|-RNjM%m!{hr{!Bmc+f+lat zc3kTkA~^Jm%^M1yr(lg6`k#p_K3}**Uh#SLuc#3>O3d4#_PZKgvgb&o8~wQ2pJ@fm zr+~?7zsCx=l>)}Y*J}Sb_oHp;etc>ip{`kJ59X%s86G({c@tA8}?yH!AGO@ zFy%_4IV!@>G@g?lyj4{gKbeNwa1PN0F{*fsUw^cF**3Ct$IW6RtR zTzMr(bQ-jtS$Gp@4%I}Ktqv(){ekXS0A2uF!B*0k=!B@YetaR(^mXf-`j?I*gtCUF z*s45%RkLae5-(4yT2NUormEU?KC@t2aC|z@A=vZ+u9o}J@T};BbpM=TL3VLS z8)eRcP99lqD;l~SyFMlXG`V6sX;cg^PUFpH;$<%%I|L@uVhwuKRvM0E{R9*BvusY| z1)>$tfHy@RMhu8KDo-$$AO@gNqK$G2zzm|v>J5_$$62!A38`>xJH6B%IQb+wfOQjY z>jgDe+nzQcFXm=nH z-mOI3&in(u5Pi9~h1E4v(;x)L1T#};g4zI9K&ihHxV8msiy7pFY|T+noYyd652cf> zP2^BpsUvV!COopFPvg$L5>vRQxb}=9s0Kx;lg9qH58V~$|z6AaNbN_V|AP@Zb zIYxBJF8-YFY~arP10Z9}6^&q4t<>}vS;;qOO3t68Mh~x1U6!_!N)(4ArNa}TK-SZ*ESzh#oT5|79p969dgk3Xk=WI|Jj@ zy-y(+)RemBHteNevq=R1Ot}Mr;~2}k_T^%$YAM1`bkx3+NARA8cabTFR6sX0u>iW{ zxM}mc#e4_+_+K>cMQC@4BIiZpj*0m$QRKR4+$&C2JTJQ7H+%3w{$~9gR)6 z!Kn%U4vU?%)SHGF6+5+^9NH-upy+CfG0@AKT4`t4dIQ+TafJYfvyDCUFrhre$Tr+G z&~^vvdP!5ipGtSj(&@bgKLl=o5P0K6fJnsCJAg?5I5%Mc^OF+LdkcO5K%$bS0YZF@ zSIRlUn%qD-^pF|wW+9!2h^ipv3v$(G<{px0nME{WCDnfy^>=NUwi1xXV`Qsw1bpk~ zqrTcO8Z|6W*Ol_F3IFM^EcA=&)HQ09qr1lZH*=wkYtO2_YaKa<} z7J8RG2t*7>MVs0+K&tqxrZs^yTji|M9I1h3LPmvWa-kj4Qm^$75izyV}dZ5N##$RH-O z5FGBO6P4OFicz`>bm}$tgPWMXNpJXYQ%sJ8;7Z)8?d6sk&Yp67noEMmC%+9m1aF_y zYo2oxCdopaah(mAM3|UF({q^gklHd$42xGl(ww#scy?mgTbTG9Blqlw<)oLLV(R`+ zmVo69ykuWbe5b-2_%(`)PH*a`ui!P}EJCc*jhF2kwyzIyG!6`0AKQsV ziAh0p0=A|&d2ifu%Iaoj0$d2A+*fcuj5Pt4orp`Lr&t=!^ttHwwjwdSU{kN)q&`Eg zGTB6ZR%|xzXoObKjN}l%w&f8#jJj*s11?@MA>kPudye(3(he7XD1{FELspNo#LU@NacMS zhk3PKFDpb9dTKlQr5{$el(42E0Z2n=I%Q(xCAm+p(5Z^Lx;BoA0T`Q3~iAF99? zQ&?TI=L6^sSLQ5_c)4 zCsjW>(z3P|V=N{H#1?As3vJYs+&?UR^LA=msG_oWqY9rlO`jpghyR?3`|fXh+nYMm za)GFk2f6#8iZPU_DNRFChkKu?!#yN*xcAXR{TTtYi7nI-g5g$cpU`Jk1)mUHL$$*x zxGhjaQGdouovV)B)Q=C@5j;L7Nf_bDhoVfmlBt?}nlArKk<#?P_wj<|)eik1nxUi7 zZixi$icHHt5L-1}QmRroC$|^(=5V>c(m4JqirTvaNzwmW@nqubsb{^NtX6+EJTyuj z%52DCwR)D^9~tn{{w9}2&rf*sI$M8f{?UuX3dCY5!dw=<{&yYxPB3Cuuns<#aV<}` z7Y0(wie9PDw{!Fhr&A+F%JyliCWFb7!pn7Q&_kq>zRG6pg6OttdbA(}I_y6o$%9DODM8MFw1Je#>wqjZbupuUsQ!H zn44sU8yyGb5sQaIlM(2Ww0tl#Qp`6F_wh(v3Ci9IrHwR7GqI}R-7&O6(&rIvk(T})a0l5 zWsoy@yJUU&hT+{YZBe-=s#_t#VTCu z*hzURjmc+7phr?zogrh(q3ZZaK1JnL>Z_cUCVRd8z!0kKj}({5Lk5`-2{6OZDn4#t z0;EdfU6kUOrR$F&yj<5;(4)$40lS@nG|U!Mjb=-kJM;j;Ea3z+ zAQR^^@_=$w;(XGqUFy-~k?0gDn84Xh6AmNMqLkyvsFRN!k!REqWKs9BfP`z}-hy;% zPdP>%lr&)T&9R<=F@#eCpZcfd=kH!3$xh;!3c?lL#k0yIXix%ERWUvz)c@^ ze1Q0lFMiDAZvzC5NPoofr{8%Wxce4)^>qj;z5beU4CMeKunJTxU?SMRkhJVRBq?Zb z@npYQ$|Fb&kWcf+gED7y+H#v&Nc}rhMd&10Nmd|0_LvFab_AfBpi<@P0)l3IdA=v1 z*Py&BI*rf$o=I0!1qPI!pt)*ZclS%dCKL|lV4s*R1g(!G(OP9fU)|f~WkMK~Z&O&( z-*f%u#Gm#jl2Wgvn+*>Eg1Hh+N~PT!@rGp1FbeS#DIdYRMZ|;5I2xt#p)^=_de$ef z?&Ac1j0rx#0D)V)GM>rUhij_TVR=M|h8d{0U9k$1ixz7Y&^IF`TWb<^sFhT`WAd{a zLi}_b<<;l$DTs+@fMw`l2zW-4@s;I%zp?2xX2%laS*`6PXu*+k-rKOW!LakS(|Qnq zBO}F&=>lTZD;IG+2e8{UTrp9RF6=)*M9*k!Yw1XdCA(M!CBme}v!*D|9r~4x_H{LY z@MkC$>}2`c>n<;-SnSrn#c^vEBP2LZ9%?YvnMr{HUBZL~S~-Bj1&*;RF;*85`curG z?&VhBJzerCVwM9~o!)fU8CE;%W^;6<=$>YqZiN zQ9heSt2NZjUDq^_YAYbL7Qv>u0H)Z@Z<#n~ol}i1loA-Lj=QLi-d>qo?aT-d zDSmBN8$OICZmuKxu?VAnX?`Oi`OtK(?IYf^GV}aOzwz27l*K7~2%D%ZU*3ecj1Jvv zuK7@0Ha7Om`w1y~Avb4=C|;(8b}&w=k%|X8fBI{tBr+bug|6grAYMUj#VF9n59OZm zfkg73AUW?M@sMvLg!Y|8NC+W<6+f0E2n_>o?@z+X2|I^=i5ty)V_K;yGwB}Xx(xI* z>vrIJc>=N*kZYbzd{5%aXMwb#Pp)T`k%7Rtn2@De{wYJIg>*gENt>V!E zq#|NfVNs$A?$A0!$Z8G;hChRXgW6f(s@vIhzNX&8*fXrScx9$SuftCx+ z=^aYSoCf)`_)U44l1D7{6pqFKB(I#u7wY4g!s>||n3hge$cuj5l!|{q5||h2;YBlL zK9l@qy*!KjmGo|01FzXGB*sU@Nd)#d6X#5bw{RgD66;9OvBoRRJSZ1TooYL`(yw>~ zzY&$s`*^0Ez%L)9kC6xI2Jbd+`xd%TSKsU)bz%KLF%}m&@G`ej|x9=$D=J zFZlzJEaG>g$qw$Wlj)a1dw=z-l?;h7?SH4HeqL zG$*33EVR*MQlUbRENOD|3#s?;i}{N4G``}T-eq0xy)yMK{#!3vSDc%|i!jTSFmc>| zV>`C2q$~MZ7hK7Qawy%(e*|+IdiChx%u!^l14Qc&Mz)_uqHovv|dwF!$PKrua*znF2-eIrk@V=O<7=T)`@&E<9(W z)4divfchR!0sfSkwRY~xlMgxQ!#{ni+{K zw|oBBepkDzw0P9*+NXG#nAkDwN=PHtg(B8A>$${O73zeRw=I$q=~ zdA#&aQ=k{m_}kyej7>dk_w4wclMXbUdd!U+VN6}5)8=Mb_CJ1;Qi}qrg-XDaD^iC< zR##Jzbt71w8gH9IRZ`a?7ouriEXOP~ZLZy!WONN307Gb2`%_EapCRSksU_PJC9|cM zhcl?8mXv{d?YR^{_b{NAVNKZcTmld_rS*QK^4I*7%p>3`ys`c?Z|Vu4S}M>h2x#$? zWQbpUF12by>D0cd2@rEqLA;huAf_gRn4An^nS1@-bgIpM~xEN}x<5D7Ox^$@tB)j=Itmw=j{3U!-9)@{jE)Yjh1#r1AomzGkLW z^TX6EVJHD5oV;+q+n!QVKG%QKu=?MVnkbVJVc$FfWbP!d6^9Y%M90>yKquS&`{lyfbyACC~w=TlW$1|F=H5r z!$@KoF&X*#u!%l8k(ds|eu%V|Et6MY8vb7-0A25M%x;!%-@)>7dNlEwizIZzH8t+6PdU5j27$sP*sm&>~yWLEG z-6${Wxj=imE~;xN{1b z-kwm%H>kgCJwfNt`6J8g77jv~l-0;jL2j0FMQsV#A7 zrJhJBp9M!sv(XoLO2kOQA$)F?pJ?<` zM5cDOj5f89BI}99#!|(py|()?-lH7=P+CV}X706S60I~~BIEUOWE@!!+LZAvZX8o0 zd3{*EnKyCpww=P#C^_w9*gFXb;c(-V;h~tkib#lhJt1m+J#QM3^^D#*mxrGZ=iS!#Gttat&()!?=?6Kek*;_w1=@C<`Chn(xkT~mu;sJ^zf58r% zPTaGSudd*<;p`HH&EE8pvFiIN4f#Ug3*lh#lJD~YH<5XZO4zs1%WY*>;ch9)pXTeV zCyzC1JFFb&Gc64y7+3Ng4vZ|CP50L^q2r(~fJbZ}K$Zb!C1B=P0pR6gjZ?31DfI;N zyBCLNvXlR1{pQ)&-`#&yzY-@nTWHoPD;-Tk?7sKIVg?KVkYdCl*M_XoFe8ub>1zjK zK{vaCgh@eykE)s6accdt)VHSK4lbY)`9jKc(g=J0yJXHO_=Y+F9~SSJ*O?u+LrjP! zkooW--SKevFAl7J-SKI(lb5~|-o(hZi{oyk6OI9Jj~=i5Vn8-44(g63a;fWriDq`Y zsuvBy-EfiU)~AO|=RUAhfrBjNtn@)ku5{~r;feOuk{8J(B@mfy9*&FBtmwCF^=~Cd z_u1z4B}E&ydLuddoNeB@r0A20I6_`0Nj;|t-64W+plf_@*MEhKLd~3{=Wz8zCnjPx zY#i~63zJ=eX_kd=z-b3L&pj-iaK>R?uDnA4--vs;gaxcz07P#cKV!C7_StcdbeV8I z?#$5|?;Lim(nij;KuxWDC0<$SdUBMsQ?gJ+lAj`>5$ zrgJh^dH&IAZLD&LBF`a8`eU*@GS&E>w|i0?2Nb4RjsxVsVd-}q7?ys_h3RqMmhj+k zkxC8>gwk!>l6AOM3&WwJBoCHF*~00r+vs?JZ@n(V8yQphFbkqr;>%yt%7W+@l(>j6 z9j_A6{ESizx3CZM>bheaWBo(B0Oo!d+k)7*+^(^KQlohX1md_fxtKoI;DhXWhZe=; zk;KpK#5nzl?H|JHV1U(uN(j^X`eEOH5HCGC(g>Xj7cXo2Qatmqxo(2Mh)kew)$|nz zvb-c<0vyow8ibU={I)*t5&G2|@m&s8`#u~{mM+Ez|u$0eEC?iFW z`xQk4%LZHpA;5w2&gFK%t%zM83$BYTTw75EeFrmD9#RGWKoE>2 z1Br|{NaB^a5t=1D%2NN-g625tg@<*+>qV72ABma&3C@>ZkTG9bxli*wM}so`3^`>-z4_am;vQ* zZW_ECWC0_AAe=|y+ZgMXGSNw9nrR&~RX$6S-Q{+p`zdr)A69Ptpz$2uv0-E7!m@;5TNgWBe3l<^ z6Jz!kpWu8BA^Lq)EV8}Sz5Z@#Yjx{Uwzawr4{%l@4VxEneNWo>z?ep>&;gzfn)M~O<{h$62Oh${6u1<61IDug`^lo00(4PCGG*?Iy8$t%#k{x95}*{~MpJLrD!IKE&) zMw*c)4{}|2$`uJKXYL30;EgO(%ynW6^R)^Gu5?ZWwPNo78ysVsZyN2Ihe%n9wGKc=j{a)_gW5!mzUDo?rRb$RF<=PHH?ObmP2|3_cEm~K!Em$> zw@1XtBVU%*XIzUHP#uKa(52Yp^>4|-u+(4?^ByN)a}mXfBAj(^0*AFre1*}>A)_gz zcaIiJ6DAnYWWy<-mraXupxclt%Oobzv%0IDh?O1?hWVl<7wfOW*SBRhY3IzZgzKYN3^{ zVD6qk9f@qjrj1V!lOWyrWpb4kx`|T6)O|S^Q8+%FqJ@?rBsd=OQ1TXz$ri$m%C<=&>p9Lj3 zmV2pEg2Rx(JsUkg#q51z1->xNZ~3dFZT-}c8}XrqZow;Bd{@S`#y%vqI_Ehpw3PZL zKlW=EReBeC*J{S~%U8#C5&ViOXqE&xqKqK^)k9-71wNm7DE!I2XY4r5Xh9ZWhkcT7 z<>Ey&IGP5S_n#tk%4YKZsJd)5dcp?Nbd~O?M+GxGnuBY*(@r~Z;X!L% z$2}DT<2wpAC|g@_aps*T1qVm3j_m?)j1Ps%%0u8Z?^3P+BtJ4YbIntd?k9h?Ra_ZKa7o4wv>(Yno#65b$N>mg6YR)|pKaUEr6Y?}5RpgU_iP5u#G{ zebh^^fVvG;WWJyYLKdbM1&@^PPNKAVq+(BRL+K`|EfuYF$9j$781w1&;QiFS)X!vn zl$>$grBl(I8h z4!XNrjGFwD_BEn?5*YTU2gWg*k<&xZ+Kxq&7}N+>eTZh&c0d{hq6!Hg4Z}*qJcO3l zY-dfe`%VHJcL>^o4yeDOhJ@QS5UeA1*-4ttHNWPhRrnw^GD`bCCYZ|hlsIw6zhdT%-)`QhGr5W z5YZ=Rl-7!7BMi}4Bywed^Vqe5zPDfjS?NO@!g;`7R3*~-Wirv~=Z5=1a)I75*QC~Z z8$zLwOoPfjd~N=LyU;GYC|hW?Dy{SjpSXG>e9GK3Z@a$0?%q9nh~AIRQu`;={ZTNG z=-tK@f3>Q^?Xea`ye_t+dZR)TP2{CiD0szPTh_^H$nrN;3pqCNVO;2Rl4P-ac!=dVR-(ACdqQ^A|*$-_*rp zRR8{~Tp?J00^&GDeRPvKv`GUU%#u9@?iJ{edr@|s31sU|0y3TWYtqp6OHg>osdoIz zxa2}bbOG-y!LewTJ_|F|x>%Bq00`u{$tKTC{-nS*dn4s2mNq#H@|y64&3`9 zLTtPdDt&@Gz8L(Xocq|;7{@@U_x>Q=#*=&_tHbC|%y=b0PU98~;~{fW*vKUg=_V573Gt5)A2Inynb!{D zUow*TzJQT5>-*pElevE;o*cX79eqX?y$6%{$w44(<|os#h_AYbr9uYAJ+l42`rR;J2R2TqXb!Crml zqwLJkMeVzz&j#wqS%loaIp8Cy4-*U;d{5HB?bjqfY`6H~`CuGLsN|bJyr^C(iXDCa z><@9Sk#~@V=TI(6M~Tc4Gdn!rQMWhItR-Me@6YBYB{h}W*+)~2qn7X)CC6HrX@t9ZKk&;#tHF2>d~I#UNx408)caOc08yCY2$vlA95m)p>=5yOQ}j8PI_=WJ&%XZs;=6_!8ELvikQ(By8xI9c57 zjQDsjiL*}N<+0a6AT$G!t{A2uQ-IN_XOg1juQ4N^}?j9rEB=;=dQ(IK)gRd`92t zARDbxC_PbYa3XJDROEgSz6qTHw_(v?@tenj_h;cP!mEI2Da@?N@DFn_x+Ptf0ZsaF;1Lt)Kq)Zj`F>*%JjdzpcW+ATB*Wjpo zE_xlEJLic{>ZP&5)7*6GR`CCW@6%-?6zS~?IME3#{(!LIdlYYUos`0cL1Q1@@?+rR zO<_ZWv*9LmK8aV2w-INa$R44Ev5$Hn=mD>o$Ic=@_Y&6$>!egJ6n2{KBBAuNs9ybC zrk@F#4bUE!&`_ueXnY*dr2qsdQeaUFsnRfb5YE9`FD6{@1_-9jqXWhsxBkt<9@p<= zlv3Mq(q=|IZbeO!Q5vHqUcRZqsSEwJu+Ic^sX3dP@XKD(zJV8X5-K?!%q)<{y-Ol# zwAfjLz;8TpQ0|V909h#(B1ONIV%V&%!kn%&Zm~(d*<73(jIK219F$w?yU5R5>I~^L z1fNMeDuYYe|Eo}|56NYT)B3}ps^__SG^%h6Ixk1@qA!7Y3WP@QAxmFZA}yMz_Kk4! z;lGH0=M&9q$u8E`b@+{z7RFdD774MzAC7(kw7t~kMhH(h7FSmp*ADPx6NhQKbp_Jl z!zQ>a{{&r9?a*BciiGZ8-HpEEjXofXPY|Lgea%D^pTvtmf;PqbJVqRM%h16<8^9QZ zD@;sb-s*+YdS>n6H>41WU3swEiwot2rs?*agh(&U0$L}I4`HG`vesJ5uv|0~W)m@5 z3$wLpkr6bpI+e7Za$2NAXl^535ErrYLHr0C#TVOblm>e6Yy#;Hb;#*{uu>)zhrqXK z^E{%7dJ=B7n$VXd+#SK*Tp+w@X-2>Xum`qg$E9rl9TioFGTa-FQ`g$D2bXD0RKcDu zR;uMuxCXHE+pH>*aO>xIl7G2oM>d&$@9V*;Kz&f>=h@cQAMwl1cCi+k`{W26!U#dc zh(Q|3DW6Q^O2Y{?HeJ3{tdyYAG!xBlZ3IjmjzAs=;_UF*0tsC9h7tBQdzfm^F&vIN zqy|f|l{O?9hp-V!xY?DBBuX11&!Fegp$#M1XcUe{P#~&+63SE%2{@0chbs&X(h^k%$b*SJF5J6ZH?5}hxcgiZAHS-yjq8k|)`WFiHXmJ+3JZ{>q} zTyA}0E!)SVZ@}bO?TI=HTSZ|DCu>gx@CAi|;8hWBib6A)n`7g*8Z)e?i3QzC;AV9o zJy476I5p9~$vNhT=>%YkftM7A9x#2p51@^SM*9S;w^ zhaQvHOCgTL3o=?+%BXL{;D+%8TP)s#NRDsHu498a+xaFN!L2Aa=KYv%_)^XI%)Nq5 z5@W70w~l@Xw@x!jV5Uhs30sLX#Cs(rc!WVwIWn>Fz!RkPRHnnI5t83VjN)B5oaf7w zRB4>ox(Tyvc}(67VNp7PE7_p=Pcbs<4#;zdF6D zvfTJiAEv2}iA75c>oG7>P8~>%@{jWBb$uIlk9g9$zC9bB{m*a$NRz+}b?Gy|?LC;^ zMsmG?S&~jg>Y=B(U9!mK6Z}=>hC7e_7sEN7MP6?bo6{+s*qH8QD|O(t4r=^?v4I@n zwz^jZHwk7`K{pMHpXQ3?9 zUeVn{Py+$9K@``C;ySA}8_d3_f3pQo>-Ua#@4wj&e;hCX)rSOOBnXq62j~j0D%HqcgGh_KnoDpaM41z57?57aSgMU$wYz9A2uuo#DS^z~9bc>0&_P zu2BvN6i;F%RCV1QRE*kbFP3#u-<#mxSdE|_^3@OLa_-RM7gQXzhU4eqRUU<~|9gFJ zx}$qoWxqm|rF)=EVcfu`!?>~sG&U|Gs}R?xfeipVo@Bo07<~EbdYweaR1hwxWA*y+ z%B||EhAu^h==L6t!jH6gfvt&c*})bHtOm75uNUD98q{SrD10gdZGt(bt!9G`DZ1Gd zp;I}SOaf(7$W7_p@gk3*NQW2Zf)WLFM5q0C1wGG&5N!0?m~O$HA-FSUL1>xWIch)p z@svbV5_R!Ap)rVQen36CS>An@>!?WCRwk_-VT(y1N=~FD;XPl;WcS9{0BwzN`%1Tz zz^~Khk~+4kaHJmVw_3ZUTVrI^Ep(K`XKR6>mb+Wq$3uNxcRD-!69`opO8Y@P z-dyk?wkz*yyH-xF{X}(<4LFbmgr)TIWBT2HKzc6Y<{^DSM)ilw2K9R~@HL3r={>?GD!cddnWLr}8Pl4&p-BE_aoI*3rt!bRa=ZHbdDOO02Dz{=DHooNuB z)s_sB&`jxV8d{2TkNWY_u+^D_0vJptkoGN?wx3ITIegjyWYdo(DculkkrLlR$O`)5 zTy5c?H-cS>-RWsiuFjng;>iieIA|Xr(I01} z+h8c+g^gAEy22;ZA70>x0CXWP2H%Nx_{MDLQq(1p&UFGO~^f5W>HikaShLaOxo(wPBgr~GI zxGVoXxFw%U1t;Mlld!36BZvjhYSL#p{BixllkX(y7cMY<@iME2{pa~NrRM+2Me}3o zW)TlgX>`X2{l+n@NMfv=5IZlfs4|RKS@?%G&Btm~Is>JCBX4h<`3}sGrBz6|HJEJ3 z7MaP;kxcffXW~qDZi2~9mRt7^lUx7O_BopLc^-5ryz#y*MXQ`+czZn59;yqs$C=a~ z)Y8a~w`UaELweQ;#bD-dJj3`Kr^VuCEA?5haVZTS>W&+ICArYtr=zmKM)IqL{hkf{ z;ZXHsXJ-Ed@oe$W=i-D=>TXVuv(f2^~0?8d-%zAimgNnX7qS`XFM6Gd(91U8fJ4cwht3 zapmZ_N*-L*Z>)KR^O;(5ZzLnQhr~tw1M=LUu{FMemdcKE`;BY%B#B>AN0Q|waoJ0J zT1>U2OpAjp7n>Frj%T?Fb#q7?-J#b|K3_hu#BaZ2emlDd6n2+*iNzT(kqmZwz%J=W zeU43{GYn&=`Q{>t$p^$3|F0l?nQ$BZetgES@mn|(ztNevXim|KIeIBaZ{q096n&Z6 z?+7juV;X0KNZd)@(#Kod`_DXl}r_HT!b8D+Y~g-n3?5rrPGD z8K`ssUzxKoc?>Q#ALnJ0*EcpdA*UN{J{nILsljfuOH-2l$Oq?4AW8p*H%zfa&%I`& zo_p;t(gKM?9Hx!nus4jpBdTzJ+^7ikAZ&zk*V#a%>Qvyv@)IJW;H2ecH8tp@*vA*~ z?``}`eH$%PV@mMynzzXs$_@@*#=lGXm-;t)wHk9sZwfWdc1pIBqMqX4?fgsqTw#P3 z@vM!la>VkD8Tb&owLWarQa81oE@A%DJj`RG5=!7QLQsoN!9v3KDb)aZ?snKfTZVZf=5WqFs+cJY5Y_ozFE%3 z#lE{;ja9z<#tLXJHqO7uTDD=~qg_h7M1JPVhH=3@8f?acHyFIB#8>g}*2`6lFOs_Q zg|t0p7|$oUFY(%Rnwtamrd3tL_a^-N7wLC?`k$pI2fQ~sgk24fR>D+o*M0hIr~l$g zQr!b~Pq{G>XL79a^e^&XTxset&i~RMlJbKd0|>ezGTR}5;Y}#h@6%_Emf+~fuN_3$ zb$644igjU(Gu>5O_g(oCn1CZw(r11Bbjm?egHvg6hzx8mpkSbM3)&94`RgF|#rFTu zLOR}a(pm!1cMgk5IRFobU&((LClA5FhM=ThF~&Im0u3cVdyRyb8KtWTo+WYZrP;NH z_6opgzGaQA6c*Qx&+!EZ>wd>LA#qFbGExGX17pw`sF%`42Z8b1rNL22=VY^-n*9QN z!u_){flN#XuTFIcCpO=b8hO6n;5fqJaz53E3UgOc#$_F?$ZNv+a!V$H})&p2c?;q5RplkoIt1v&oKm$HrU zWu{3v65W?ck(KlZdV)0dJ4gh45K%e{njn2MWo3zWhrWU!e+2|SpIR2bw?Nv*6|r5E z2e&uk{G#9ZJGb70-l<-mRw1@6ji;zYdO&9-2DielDUqs3a1E7X0 zy%(rz{9>heCt*CZ%6ncpTV83bhGPa0DLR{m2dUz;aWn43nMna1PD#^T(r%m|skle3 zvYTyfn6M;%x7Ma6->qFjsO-#r7y7d!!s4P+x_th#KPa zs+u#5X`hw*+x>ZTAmiMSF>S>5!Qf{>zjifn44O)IMs5|A4&8pv8Klg*D@lsi(uU_WG<-#>^JPMRm|JJ@izF*f{a7RvHWOYHH zYRJ8?lz%JSHbFuP5mY!)GNzY# zgod0$0N}DW+fX^Ir(<{0R?~+mp!5j4TeWCdh|{1UOT9v$9Ya=vfK;TJ{w@~l zW#o0-ac};CYF|k&H3Vv+bCl!0x9bd4(Y+r9ThJPRwc+5}18bx94F{=VK{U*z=neMf z4ETaYJDTUmyg*C2a6VAqE9&2xbl@sTPK-bWwwzC`EwdH1G_75`_I!_W1PU~CoA#_J z{#;sM3PN!y6M3)9KViw+ z_B)oKi-UJSVT?Q2cZUIeddiW5lh{6Nzw?N^sMH-dyZ5hK4I@36zH^YAQ-krl2?_E~ zAPMguGT9>(Dd2iByd{8Ng3AY`7Xl49 zqYsV@_bK^Dm5!(f-oZfo+ThGeX+P4BvzmojB(=NRM*VXL=oPdRY-M6&_%K8+U@Jat zhx`%UigRRWG+{N|Goa7(h{NI7SlBV$eT40pV%S{lHy?xNQC=2()mjCh1fw!{7NW`Sk%g(14_0xeCtjDCsZoaC$a&8ObyGkIty z+D!Swi}qpi2h>{&O@%s=)cc>pZyp@0-o$TtqMOd&;o?vW&7_bB3fYRn;y9&Rl7oshI6Ci_vGSTIS?HMIkFkPcQQSW zYuh#x^-e<_x2*mJ`WPhbTXBM zAr8H8Qr2fr=a0#n^zx;8Xa>^bHY@_MM`&A$2qu{i29iMa=`!T^h|@hGJ#XOj6(Sj& z^&;79TudaW+wg(L*U@iiJN@b#@e54f@Oen>@v5(e4!~r67nLaG~h0;s+y(^y=O@dv_k2!KNlH3F|0l*tzC5)50QG^=E#1CsCLf`cKk1*O6bEiu^d zoPSOB0W|@PqtzGB8-K6E3GrJ)e2oLV`7UY^oTc}p>(Ek8YdpJ$xE<#JF$TA#r;Enb1sXVA7 zaB)gIQOv9H2D&&z4RQa2wrc^8>MFw7+yw$G>;kdIHbqoabgN<$wYXHnBM@3r7Sbg3 zL0h#V(AKY7qEwRr-_0VoCzqln8kG2KKVPk)ZAvH&$u2b;9)*M;golvQ2p1OH@Q`dC z?)uNn-Aw|tzCQDP*?aG~=bp#RIdkUB%$YF*>;jUqrAq-=HI(^U=aO-Ennk;Tob7n~w9cd8qNzZ(3?n*Bk@&la$31!moGLS&Y>*$_;llt9? zD*Cdm!%+E=O{fCgEEBD z+EmbBta^7s)rTv4VWx-qR0b!x8$O$=xFzaR+i76e(|rPq^J^p9IWuzBtk>XZR zW+oG8uhxnk8TUy$skmJ;AU_!BYofJ2b0bw&c^5T=k<@)m)!$FoqiwJ0VXRp@+fKpi zg@F+Q7?NGr7|dD}OO_TOB%wK3S7bc1zCF!^4jt{pVutUzS)`X;5Od6~t)>@tM|blJ zM+NUL=g4G1W9^wyOARdlgG@zx7W1%!%2%kLLxw|({_JLYvL_4YG>{=NaomBkMBl!J zK|)LnV)3Wah{Gt8;pT;0#Hiu^T`)r4x%Xi zY%0p6(zul~Q5-d~6_ch-+B3A+jZD^ZguwU$jFa_?0OujY4})UJ@O#D{eowvi@H>|n zx}1`Dt9aO(u6m}fCDq{2D*#hKtiQ%EYB!DnMh9jqmrCslGa4zoQTvQdwQAW_kKWjC zU~bC#_Lf#N_Q7=v;`q%Xaz(ruC<*~Y(JI+Ct437$;FM>8N{OGvN7)PyM;Tqr&Bg2?IR5i$i*3QERZLb;T zJ^Tr0Y~YO1$gl>=xS$R#dFLjzzwNZzhxQ2>?e4)=gtsKJ8NsfE_ajgyKg(H8Y2Kq4 z`?OE#Lxv+XiZ0=OfGY}Pu03{Fcl&m7tE`$|q(~HPeQmwIqvh$oORJ{9bIrSDASe*o zNS^Ov`Pjs>YDUV(eV5=I<%Fbh%4E6Mqm#aw~!HBDQ@I$79pG zkJT~w_6Yc*0AHwlEMjP70(>{9P+LdjJpf#q3aLG~e>;b4YU2CRdf%k741S0sXc2> ze`^oGe`?j5rnNAWZi_A3&7A!S_trx^1X^hnobzahw4;Gzc_>#w5q; z10z}4`FFAeuSQK~DK}^x1Bt-L`|7|-`kqtOX6~|D5!j3r?3T>O*s!EN+-R@T$95s z5QC_1CmH9n?*Meb;QRW@-eyXx_IOQZQ>NFkkz_5EV=^YZ*x+wa&RenlfT0N1X>g%) z`pFat{t;mRFGk&pw=s%0q-J&sM%5x%TH-0(av)0My0uP#>#R1cp z0Xxjh=O9PPqo8Vc#SIcgwjhppVn2~$eghV)MUV<)q89h>52%qu7QHQ0d@u2LK5g+q z{o!^8J}udgwxV*#(9vHrub(vYFao*_jBlHRWUU=Ub4a_ko=y&;HF!ia?d?(bUXorO z$95h5;ljC{soc_bNZ7ItU;|i4ht|qk=x9XcCr}Q7;wV9~SEVK4(aGEEyQjh-+?;;Q zEi|RAm$%sWASDJ_EhlyvWtWj2g6{JU1CTyi`ZB8Vols>hP(>PxEx;WnS-F-f0feW| zQ6(sF_MDh1fzU3B@7u_grxvnBz^br=0Dj!KjjaBsZ_xYD!>8#5DU6~B%R^z?^V@Mm z6Ly=X^AV%aLL#8AO3nkcYVlruC)%Ao91tf(Xcurv8%MODErv8Sx~&(6UYNxt=~}NU zJc#{)hVx?6*Ulh^c#FGapil!~$aWBjQK;fvD&&u-3l;hHls<_jN8U#JUOs(^YDb>U z#2q0GZu!y~89Lyeqd$B;6>O}d@c5mMlBk~B?gSd)3=cyXEKue0SW>FTQ6G%5PG2{6 z(=>0;!)$b?q)p0tSKaYKG${6al`EbD+#f{_j}bZTk7iC7O& zWa3esPKLJ-6!o$+Hpm_Z#&$QZe+kCO`nYG&Gp{>3nh~%p!e->F&z=2YQ-y1*GUba=uQq zQpMIs7qH(Vpb`Zc&OginJK4echuRC)O&UiLL6%?Z127F9S~^~5S*}tmZlJImop>~- zzw-BC*roL7+xNbmM%eW2M!kg>?uuV?l=9c+-f9m8;SHwPb<9>AE;WYmn}jz&HDX$Z+F9?H5AQkS1lo1TiWqW*=j zhg!ZQMggGo?djCkRbSS(=TJqfJ|F+aN^?$W{Do2nz9}--&Zn!n_VaRiNG_G!xjBCP zd;HR3)44j>F??7~28qpZ_JTpk-7m&L$R8Q8c;vJHpR(VHV;<5+#K5wF2{CK+3QBO@ zn^0N%9ssC@`iE8PJ13AU#&h`9Umf8uQcm;bUkh`Q275Q0*VK0qn#Yt*2(P6Z7aC_L zmCcN=CI8@xf1B3U0Dcr~r`(M|JLTzNP98-AVr?Vt@Q19_o2H7Xj8queNrGfe8Io1X zbJ%$u*ZNFYaRLv;^2Da88xFYep2OUQ1DBaar^Ms-opt7m=yxqa!>rFEaj=U+_@p4= z($hj9wr}K5EP`a5-8P*ke!s(hh5^K>ufcm7!yYEW>jH7!H0qU1m0l(&=wPT7Ysy_+%-I#n?Shtoxx7h@RSc8_`L;JMllhDyorQ92|J@J2qD=FHnq7 zvo_fUZe^kie(6K8HH{j|?ZYIqM+>)biNVcP+(d($o1ijZNl=-4<;0Z9hW>C$X+HN9 z(*1$~Ts|M?%R_Q0mCI&%cfVXF(ZxoV;KyHFU}XhBXFhM2ZYE0CsdQ*ysB~OVI$a); zOQ~Eo%e(vKGKnt!t4ptak}yoD2c^;L3BJQiZieOUI}&(b$v|TgFBxG!ApoTi#5CDa z%=&pTdm>58{O%q4kL_y>S7k-!Qvk=gnQB2gEb5?hVr0$}RO!*-?!a+A5{sRHJ8+Oa zIJnpE#Z@p?i*^8GkLS0TPonYI%C1wiU`%5&Sw5!8nF^=0{DAY8C3H%4Me4dyZ;C*Q zUtrOfZ)g4oBut}*r=Sdr%6LQiSTv}Uzs~!YogDsFokY)wpD7s&bC*%nyOSD4SC_HP z%~K=4a$vSavQ({$1AR6LZB#s0 zWkxf5DboWVP>JrqVk(~r0%jWLHEKzMK%A|Q-l_9E$*H^GrdYCVRJ}wcA2I5;5K)Hm zt8BW6`_v_ExA&sG-`U|X=Q&tnrA6t4&g;?^C0}z%itCb5m$KsRzS6+KvJrY|pfd%I z8fFJNS*qeTkgV!me0-`j_i_$&BS-AEa#_Sib6iv==VvR}I=c@s7tO~o|C0a#flC6R zJ-KZ7stEWi?p1+-(XP4-q$Wpw{E>|KRG5|_#k%3)l$1e?kspNQ7;!_fhd?^O!0;j< zi;q;SxE5tH3Qa;o$rn_BMgyzv%iqPm=qYS37{`yF-JBvsS%Tl5CA&#-;5Gu$Z7o{1 zQqoYVmGh+-NGMixC+rb|Q4wD?kxfAhor7DfY8m&8Yj2mAx{LhSRb_a2eWc8>REYYt zFp7~T!d5~p%Kp6BZv!fguASIkVGOQBb~6%!yqzT zz9Ke(xjl{f4rUxIVL+JIKpCD)Dr584n73mFg1KX6dBPI?FGrZcuznj}iuRa~1S7l| zk{@U4vrezay-j?)&GNm3!Zp&e8gb_A*q|dBDW4VAap?K`%UAmoPaNS%v*Y&VdSEU> zH{T)NM75|VCZTHBhp4SYDEtfKTdASig{JTP1TUOqbV~Wnz;rgbaLKxtEtlKkVmi`k zGpLjGh74w(DsD_gsSURYFExfAs9Yz^VDKQd+q-Okd@Hpd#PFK!OBVy zvhMx|N0za-y;ki#O7Sq6gbG+uwtHTOeP7zd!D`etmBYMN-%BDDUy&CBN0N zEb#&~V$chQEk-OAZ~gYZSX|Jdn!G_6nsBAgJoG$W05F9v*3L7WkJ+*LoYi!GRGE@{ z1~Dv>dot&)qTE$f0EyrD9RSv>IMVD&q)cXL8GMb5?>?eh?6jDHJfw%#x{@GvK>-!@ z31r80A0dEG1c12+kihXq?ErAs{e(skbO|7&N$|N13JJQpfd^N~O$h`{AB2FmK0(0K zDT5t#dy20e@A`T8ZJ@yo$<8!v;MZ?tQCJ3>(VG5YS|fHEWE9$%W)x!AkwykrmlhQ$ z=Q_C4a}sUtf=@0#$Afw3bd3DgVWWm;m%n)VF!H!&y)8l}m0fV<2{9Bw4oZOW*vQ1& zrhg{~zOqZZ+sa&#k&lfa$hDRAvs5Q-k=_{fa|s1S*2UMU2(se>abMQ_J1G1>PnU)G zrpJ?`1<^%0@V*IWo^~t9#-fl{lRz*x1ODiN5g#y8`8a@j@8|9tz}!%JWu;tW&ju4kRZXN; zZF!j}Q8iIp!({4}4_ouP%anT3U>bz!WN@%rl9-uO*wBn7xfQ#c_%0-1kLEpL@a!mF z?l3by3*QkJ$j=dfuj=WATF3jm)m+~$xK2C*GH+&21MW^gK;>}O$2rsYDAU5_sZc+| zfY=Et<;4E-Csbk$vhfLBeF_G34q}K=ULjw_n2;-ZLOR=%K>}W$?cUm?_Nf+(g5arP zS_?UR9i|=7g2W0O!Wea=&^D5agY1wCkYa?aY@0@8lkD|Oq9br2u?n6(=$5{dN?3cC zP(qJ{I#KN((9&|=O#+>)&^%H+QXi0W1ah*@F_CXT=Ln4>p0Cw7(w9TbM_J>DoUCya z81gS>0p;i=wnymJJbdKc&#K4Zn8!ZeeS}qyS1TTGgyJ!s6_4+N;&C|cl4?iXjUi$* zoahsWYpSOKV|-^FAOTnj3==Ds)i{iz;!_fU$BySdvH|{W>18nLx*ePib2zww!vSZ* z91bqz&GR@pggLPEYw)AFh^hWgC-W{s^`#<-j-L#OP6O21`0p+HZKe9!zPP#IL+RD zYl2x5$kbnYu#J0wD7(^yZMY;_s&9E03n<3X@8t3H+d%_6{@gA6(8&90ee-y}{E#nm zOZ|3VJQE3WQ@h)5Y;>lsW9}vLL2N+gmKyB#(%^7RfIfbg82tG3iv5;^3hH0ok}6cNXVIg^5L^6x6-=DI@=RqhyOwwwW||%V{Zat?{*Dct95X ze2y<%`i4tMQ?TW93|R5cHpEto|#VRC2wP*p=_`JF-V^eP|jhAeWKgawiLV7?l?14uZEx41}k!Abd49;<7ADwhhn6j%-L&7sPk2gL<_MuBlBNj{nP$lvRaztG7o zj=w!tj3cSrYDP3oMNfS@r-=WIYiL;LrfE0ae6h1@CKo>?GZ=~iZoeI!` z#2>1%E&lk5+P%e#tQnt3Y{Zd67&oW}pFzIq3yiWYGK$UgnJ5n%rzSuMZDr>H=3GDI zZ#aQOwKKJn4MkX|Zl(;7kQF29Mjie|O5_X5!%RkDq0MCQO^*j&b<(J1e(UACY47=i z3Jx2NP2=*hrgM?$npcf1!1l66&->{M_l(w_WxH@Mqy>k!?%dA-@BDxX2pxd>_$3mF zJdd3kK_6*)lgD3FV14h`34(}u$HW(XP7oVGYY`Q)=BF%OU$cQOmg^&s6s6GsDLD>2 zU3%JldgWj$;m${SSD#me6A181(_qfOKFD$LiU;X~UGA;Z^T0qu(5$)fG8( zQ~feX{-dnVJZTp7!?!nFTtqY^s87NyH+$`xQ$#wo1JIG1u1^DgZ1PXD5ELWLz(LVN zl7*Da2l#zkj-BT)<>@y@>F1mVDVi>q{!*a@`EW!s6(2*A5$qtlSLfp@|2$gnL+jc8 zbEt+0{ma?~4wpN(PdZe0&rlrw6K)n9i4K{HS~s`lldFa05@iWj59oe&71pBmJ;qykvn#XZd% z+S8%*{uZ$eUEts-Ij}d^g2c>&{G$-eHG|4chsvHrA$KoG+1C(IpsXWFh+g{mX>Poe&}eSmnCI! zF1#r@rqX2k7 z1VbD^;qA>qN3IK?fn7VBo#bXfC>wioc*9>wA|_$U>?LaLBR62Z*4Czt=fUG{0MQ|m zPC}^%o3qfa2SZtG5)DTQ=u0YzHpULPS&5`VakKVk^!1KLbUSzQFW`G|?n(~T$M^+G z6GyPY%E7wJHWo2TEV#vlCN&EnFuzXDbj|D^ljHAi^uv$PodD@&o@M!$#aMZcGjMFx zNmXJ|fuqn^5v9XvW9yr{In1VNhvD?% zevt6Fkb7Ywv5^uQ0Wc@+{nNMLY{3=`ZrIVxOjyvc`6^J2XS${t>03znbwK69YMp#M z+DdK}*Z0M<4xonjgL&cg!TBU{1@FuXB799#`7qUm**nvB82*hH_tWPwC*uA2x*$V# zlA|6+`81TjK(#9h_oCv62W);0<9wfL0$8ZK08$rW2X1(RMoH9|)lY^(hpD)o;Qz17 zqqM!oTnWgK+OsKPd8u$b@31-vV38SDpLn*T-M;p+%eDm=($b7I0~Q}$GV7>qT~TpzBdh1(;* z?qj$DnZ)&lL41>Tncl_GBTDxYlQ) z|6uRk-;DFFvik^VW#9@qtVz>Du&Y22j6cEwgSm+2Bu?4vl!Z}ddR>Sk2e@q_+}3ru?P!wQ_Aa)PQ154k zJBpPo!Em=C6ZYPZ4&$K{xB|%U+ddfbeSmyBAm0Yaw*c}dFeUfFMA!>_j7mHK@@;_p zQ9RR=TaOXskK&;ZkUy3nH+f8MI&E?TVkY)%L+DNCb?A+CExoy%19}BrKS&2okM|8F z`ar1HP6p zsxQgL{ys^dz5U3x*nMiSN2cq@lgMmi$d-}MM?PhH!jbd;dX(fi+aIFsbR$eEYnoZi z|9N`W@4+w5#u{r^JBaB{xk3^FEyt*BL8jKIKg?eKc*!z<#V4>{!Y_iQ$MBYX%&x6q zL!8;XuZOaQJqg&s&I44_c6Nl+PdDnzUp)^?UQboyF7nvg54+O1kDZ^>7ENfh{gm(qx%q_IU%b?1-f)@8AX{TsSG<1J2 zw}!PJJY2x1)|1~+XjBZdQ9K4gsmaha0(G{t4L;*uk8kO?r1= zn6F#;(558-5*Z;k4#hy!!m6GCFYR9LQ9mGY69|bS#06g+1}-q9?Sf2?P!lq-P{h5@o{*X^V1 zZ64pCl6^oh_YgjR`O2h3@0T691?wvy;A!fzcUjf4(r!JmcaViODOJE;tntP&U$76?T$X7IBT(ZyCkvc0!U2n@>>t% zTiP!3-rBaoP>L&?K3D0PcsBT(@`+GN)lydk|3yhD-Y2I3BR670pW|OxBrlWiejFkx zEAC07ryyhnH-_m*qSkbXTD>A_1?aq>qd4@tYS@b+Yo&^%5bYvLYiEtRl=}w%K5?>&tq+fqUpZE|^IBu_VDKxfl<;mAx!+yi)G%-gBI@0rJOj~$ zGZ6b!n9e}7bRWIxfPQ+_vL-t5u;vsUglGkspmPwkl4Bq!Flx;_j=E%I2G4?2XctBSHyMzYIZ&l2lvQ-Ukg?lw2W=KitMq->7ib@xeZ%#uQ{4~L z@>{n<@hfctYr{jAB3U$Cq{UIWo@nh|(?hhZ>|G#vqE2T@v`?BX6}B4bTj4b~sK4qU z`-`{AxuzFj`gG~YuyZTH3!4DvcmwyfGzo!m83*un_Xb!dJyWKr4Hp^_<)2yl%^h(~ z2CmOqi_P@tz^!rGhhhs;}1(;iA-3Yv3v{!vGl$5 zgV|y-$#Zt<9D}>yV@V7A`}C8GH1fuP7!$bh4wmH7;x0fWK=-PWm5ZXRKy@5;7f?DXYVa!P> zlfEGPSgA{hhwnn^^XfTT9;N%dCX-|2;29TIkTu~H5A8`~aBm!pr`hY6JJ6ki4_<-R zf53MSY%Yj|;e-&=PLAD7O_h4Vhf{GuGWaxVpW?N=j_D#}29u?cirB{5@~Fmu0fz(D zc34UyDN#XAur|{tJb18%GE^@pF2H-y+Z{aZ8QmqlGCrE4xDq|+1l*GK*alDEb8ls- zKNfOcFM+NfZi0X`^cfUMQib3)s&rW+HHwra%|gD<8r1EqfOs#&Hyi5-GSi-9>#Up1^?p1lHjg#uIiWEl2Bll7n^kupFxcl38mt>XPR#cUq6)0oxD~fqvOC z)0-*q{c#*CqH_;#utMYo);jGanOfA}iy^WIBPv7^B-CpN4lldpq~I>v^Ju>nDCt#BxqdlJf zHQ?uK4)>1T-V1Xe%-lhQc3O#5z7RqyJ&a=|Eq9ukpK&*gcK;p*2JQwou88J}IB25- z&1D|u%p#*lH}k>>e?TD!QuIh_;`~U7Rl1W9cI0snBP}FI%TXm!)kD$L=K(5X1#jN~ z-W20a3Eq_8O$pvq0&i~+-tq|`s-zvLnuSWqx|cInFmOc2X;miJj;;hapbko2hW@fSZCM6TaE2(kP9V43b}% znXuS5IAF+Zr1QN72PAy|J%df0h+7M!^UVR;h0>wAyaF7eVYWRQ6N3zkd9z1DV0QQ( zxV-*pc6O>-r%@W{lj*$4;1sL+R`Ts^z`}!fW}h(ca?pukydyc~hgAy>B3??yOK`rO z0)n=|yVcAX3~FH_$T=f_HR`DVy`H+6R_EZoFLh@{stRM*b}Q8qU>ICBYI8UWhNomA zOwTenqLrMeFmpR$h;qaCSxFa}p+{XMQ?nZFOhXP`!W~*fI{uV?uPkAF*?Pm1>cIFbr#(L3Go3{GoK^j zra5Rs<-)y{M>X`ygC2azP81&saXCz?{3a@f$rVa~v$yqj9i zU=|y#ggmo~O}K8uK}^LUGB^QxH9u?58ksTzh~dFNyuREW(n;j0|4+dfConRhNXUYF zyfu^~2~btbZvobe37ydemc+9#Q{PFD-1C-@JjVVI5|HGlL6AJgPj0=BA&CcpWDUV= z3291G#g0n1oCYWAY(V7@NV)@Cc_Yp?Ydom+CjS~9#WX+kuwQ?6GG&*cFVg{|pFhoH z?JnGiN+7%UA@UIKHGgXhLmF-fz07zkGHXCUc zEuUfLR`_v#<2PiwplzdV9!L%%<-iJM6nlMxYd>giT15KD&iS%-fg(==HM$e{xdA)v z3fR-Ji#gmBERT6dT4FuWr=^q+ zGiKLR%*w$b)7v*7t@NDv$Kgc$YItgFoyaAFK1unhSC#LWGhE8A;qtGTcX`Z$;mPtp znNpsHbL}9wkIo?x!kV5ZsgBcew#OCg-sP}WV?tXtgD57*I_pDu@m;eshueZt#6sEE zNzQ9eYNHc50MT z-FRS7Dr+-bDX1o4uHWL{XnZT@@ z53?z-ZZvSiY&lPzWOC1U1`n1nllwT25HPzn96qeig(%^!l)9qA!ou#ewl7w{@PXFB zj}XfNAqZ6#`JmqCDM@R!O5Uy4 zr%?0C-(mVkMBX9Uv}Cp}WP6bwu?6EPX|PrMG?QoB`bwxburtMPwG3oc3ZhYS55rl= zsAAG-1O^xpNXN3E$h%vyFFC|rY)QyFcccmx!;6Pzkr`9F?sVb zYL);_BfRZ6MiV1geZXrnkimkp;t1<7yeu$jhW6P_u`_}>P^5a>eKmyq@=wDq2a`td zf#RBd7s|cT{?&Da3eT!cgR`o3S;!HtpF6=^=6J(YA(aKb!Wr|ALg>&rN%N)^yR z=Ky8=OIs&<$Kbb);n;$m3(j+{pR35q?ZVCoa|QxPS`G}R6oL_iuEK_bZ!lOq+$

`7MSQ%5xu4*W(TsbvnTKT3AB2ILMT$!?O6+q?N3$?)c)HZk7LIJ+ z3h>sS!E*J$S zc?!8JL9T2%G>crb@*QT~!0=dqg?-LWGYRA64=N_6S{2g}+l?x{fjtn>U((Og&VO2c zI%W6xc;>Il@P*56RN=@C@PFmRb*!Y94Yw&nJ zLh!XVnb0cE^?{4yZ7*FSqd<7D>GdS3zCF$VY|aIHjr~(cObDO^FJz&}I>c>?fJAXG zTmc&R3yDXgI;pbR6hxv5NVA1EncfDDBIuDygko})6 zyDuqJZ1ndb()E+&18g3w;E!Wi=dgNow@+i;Qu#-qk0HxD*rx=+dW(BV*nZpIvRzt; z#a5iT^pNU#aR+Fa_eruMV9D~g@3y7deA7b)#+G+VEWU{<*-lzvjJ9T&&&s(;;y(M? z5a9?Z&yB^=)*h1kjUD9glcMlf{$K<9*;5;TK(@uq)M3WKe03*JI@?gM3&M(bkWc?n zs_8u!p$hDZywAJ?C*J0?#&BS8Hw)qD#2{wSh#jK;6Pq+LL(2S)>HH4lDCFwToPH}@ zvCRk^DotC%Cw|L5Mefh`kcJHVa&mmuH{hi3w1=j2RO{1X0g$@yGF3ZEqJ`0iO2Z9Q z5&Yuq7|;lJdG{qX!eMBH5sN9Q5pIpCeWDE3&#V${a9i)PFnh(r_GC9Y%znYS1A z%`lzzAj)>Jf6>AM>-P7?;)s6%ZNc_bo{we&B&DV;4Ugi<6Z2WeA)tm@*94 zo18eV02^!)_#Z$~C{=@yIy8xFlhH1<7#83jL_fRJ}Pj4(nAds6Mil^9R`bPpMv*Ll+k?-lkJ>2rxD#T#=*P0M{0(7S(m-muVx!VQyn6zrB)y&FR6L=4D>ZP8H1B zNk+hKlMb+A14wejx0WDI`q!ebssFVEF&z>_u0XbvEl^+(4{}|D-b1z(F9V5~`V3}w#$vTWoKBJ-P{q@jamLn4Hb^i1i9l<94iQwN zQ0Q{cc>@Hk4^S(Jvp33z z-Ibpq3H>d~6j3{5%Rgz%d+(`UN6N4#Qjw3MiXJX=nbW_E86n}gDZ0=wRsd0iktT_= zw(!QQha`{3&XnuKlXM9aU95&f8?lf*!1A8ei{P-SW$(gy2(ceu4`^LA0{4_#k=Yo> zi!nrz;o8^dBJbrRos{E%a(>@j5Q9li#h)n~F1924^1s^K*((Dg^}xV5u9=eL+KA_4 zW<9RJCQ^!w=i!P!^ad&R&NzIkC`2%wP#w07K_g$MU|-qY{^rU8WfCO7EJ29%H3~yL z*`8Ijb}HUuf)j~o>~Hy%#P}$PVr6=jO4Gp0?uUt*a3^d)sRh+;d1=gwYP+B*LY9H| z`|zG?v0*nu>hv*3U;0CV3!pbx3JVa(pu#oD>Mjt_kuH%l*< zq?0_b9)UIXuspC5)L*!bD;sZ4|C;v%sL-C)vzLB5Vb_vNzhwmxXdM_B%&m~nrwj1W zb)9%GP|0E>fM{i1fm)QeQE~f30{loGBY!lXg>`qHL1)|fqI-V;PjcPKBmp=gKR&484 zO(8~V*m#evxvWKy7B8i!JOd%XK79+Z9#~ApdU9GWw8{~t0G_O4=>Lr1t7AwUN{cqS z2qPkcO)b=ln$6_G0nT06Vwxr5Oq+vRX-%~;zoxqT;c7L%=BMswT0BN+&1P`Tj*7of zy(&Cz<6jQ41rM{}Tp$a;O}gXbYKmK|?M5L~fP73=i};i_45V=2?|dgD{JRPo^J}XI zXa76bg>KPDf2aC#q?0~$vhpVShJhn?PJu=eUC<{(BgdGJO^T$mGL`N|4Y;+|!++7^ z>E)iVc8b&o>6GJMN94-6w5%vfZ-%N?K(ddwasl#df*) zmn1{bhGIE_*%hKmVM9Y{;M;%4B_4T`@_v+Yb$KXEsJWhgErU^@j_c>s^iB$VTc{p% z8V^l&(h!Rd4cRjb%U8N8fL5G?V$5iR4?}W!}-VV+8R6XCl)PQTJx>^m=0_1hg5pvw2?-lp}~U zzwt;$-D@NV=)w=Bui|uY`)AB-4@KIU%8bhccBCEl-fy6$MED&m_X7Y$0Y}|AfMa&( zEC&-wq14HWdoojTCrA(f6!#Dwv&5VJQu>t`DS?gLdiaXnK;LqQ;r~fWFnMKxmzq4I zY9*dgv{A)=tN9V}VFtx8Dn<;Wg!5#Vgb}eC-j)c?!&z~lPI0w)`m}Wj71sxPg;xOo~v(9&T)*Ji{AZ1 zj3_x(`c0?N$FNNIkwo+!cw?zxXmETUT8QarT_k~S#*vwgdN&GI7^TZ%Ls5#x;F^rb zv()ygD5KG=Ph&5Nc2p|K39hSGe52>UhJczMrc+xv@F@Ts6DeWfOuG{id(MreaZW8} z5s?=TKBmya2>W3wb+j2=z8$(Ngk2beGBOJIp-&kslk{E$^7#cO9`Qw4_*(E`hlXm^ zfO(Ft0iDNeToZwOZWZ_UCLB3m)Pmj%GOk}t<**i|{HeqSOUA!jnMz)naoEB{J2?~u zLZ}?g+Jyrn!P9i2xqdSPb3<}gPh(KH*T(R@#EF7j01Or1Kus%=ef(4!YA5K-=Wlc9 zmnWV$dxr?po`{I*<8JskhxD0jhx7^Ap)dkGjwNDG6C(D={s$swKMyS~bReEjn#A*I zNyhU*YwSZyOa-t6Hz8HX1kPv7P~0}@Bj=)SYF*M%#m&^MRJ-^5=#$=8&g7v<=)^v# z>VCSOXgdR861%ns6NBh3Fn8knrorIQ0(taHClN_})gr$8#S?y*$3Gz^iJ$Q*tV}M3 z&-*|)n(Q%WcFYfKK%kESSRq6Zb+VQE$!%qMubp`#kJlWs8U6kwu^mUAYCGM{_ zE^$8+#b75O;;NM9i@Th=9Nuc}4Xd4$a zKQFn>=mx7_6RRDhaL`*$yKfBm%)c$2e#i92@l zBZ$n1Ycpj?qd_{Z($2V-GCC-uNzLO-Q+DD#=YyDrUWJfs(amw(T=Gd5Dwm=F1^|kA z#XaTF68FQe;QcGO9=hm$BsdliNQ?!SxXT-n5TXRQf22o18U&T)^d{L`$x5mO;qX~8 zQwE3%dYkh2sq*T0Odc}fW5_zB(=yU@{^h|K#QQvXpC-YSS_TJGY9YH3lq)lhZ?s;; zty>8F! z`VE9RExrqEN?r|IWUJpBc^)fEMltik*5kq`E z?kD;fL6uBWx&}py3fX}nLxMMY!vGg#<_Y1~!h^9X4;%P%k1}Z~8WiaXruZ@ghf?XD<*bkOxaJ;~m0v&LS67itIK#>G~O5@Kcpc7S>Oy-7g z^2$UqI!?b%ynP5C(K~9tOc5|dl&H}i$m4nz&z0!K_B^!w3Q|VH&y~0Vb zEM6Ng!W+=W?h|H!3%sHQ4MYh`z{Bv^$GE|knZq4#79lD;PmXh&rLx$+dB7tyX^8W& zjn@fxM4w+9D{5mR+!1${f3N3Pi3hMZEW9zrj+))w&WG*cW63^jA5$hX&WE5y+`Vd| zZyziL4yk4ws?TQY3%Q@-+fDAK_&$?7D-FkOFCs-9K%}Sx7#cqgtqDPQ zldjt)Bwe?Sq~qNm!EJOK1EE<$qT;ytd)2IrthlsU7;s|l&;A}ioK-TyI~R9awR)p< zthWlUfF<{1@IC|hhayh=VnPiBl)^6m%>qirD4ncG)rYi6L!G8w@btL2P)hjn3#C*Z(;cOJpzUsRL|TziChy#v{v`6( zF3@Y>*GrX&>!lJn4P13Km!644IKDYg1+|ELIX$c19GUy#BW6DC8NpYe~TWTsjyik(oVY-xwu9E7d^P|n$_NN{stzeLm zaP<%;Y%z#?41c8525|Ya24K~Tm;i!Qq~Gvn&)bxMZ|R91o-Akvkw5o!r*F*__;75$ zO7kDz!gVbW8+(lT1ka0{mdpCCdSDVSBfnbeMS|wxZ8GUi^?)|t8$a*aGH}0CzPMj1 z;|s~w@1VbhDPWx-ZZr7S^?^GD$<%l5@}cGVRa9C7)v277)YH=Q7A7Dx&IKzrLLoC3ZwieV z06{z2Uo-GD1`wjii)SD*TH#JBVLiHV9+&Djn91N)Q5!hAHtWPAYQ4q;Z^-MTSJBJ# zR62U0xi}xj3@+3%!=&>$bV*DP&U#UxKcuc(?U`${+HwO{+q_|cQtL;Jpx07CC%@iO z$_ZzDdGXZ@K9T%7vV;3bsi2@=2c`K&UTw`*9QQ*)c08jct~crCb2LHvooatG6vH zMV+030{~1wv%mC6Y~6F(I_7XGY)sBvI}VfV&2V0mvo5K$r?s@A_ST%%zV?l>3djA=EMBgV0= z^~vgfWpA%?qPN|Wq8d}wPG4(hD?>m`+q{%MyH~*C3tI5guwFY}U_BmKUkB&7oOR;{ zW8LKAG1i#{;$bWWXssuRR~X-fi?CY^wr}UfXbAr>CIXL}Q7KE{yftUt^hi9)&nK@n zs&)3m*55WC`JhzUlw#Ixj_GMp4(oc}3RSB8aFfqtSwfg>u*EjY7A>AJqH;M6gZl9s zBHH&hUcYG@#)jlm4+L#A*(fbK zH~ifAL|9TNEO8(#$&JrgFU8J0|he>Mc=^FA`hXV(9?V%=t1`~bgDIRe( zE4|Wu<{pZ#xk$ynghyF&q0v@m!-M_xCcrI*^yvoH7R@6kmsu#(OrdLer~pU|&S`DP z5Q{)Rsl?K>RM{rq#*9PwQG;7`(l{r(Mj$GYIMNkG(#V_D1Hl9%zy;q3nv#EPvQeE_ zw=I7^D8IuLijJCxq;!=VcmLoE(x)b$D~3Ibp#7+Z-Bbpw9FcKY+no^j`PB71u`Lg4IE!fSqtI2p6X}GqMTOEira)*IR(X z+bgJ-hC(SpGC?BlpNhvKZb)n&X08K7{vntl432PuP2%QHu?5@U#*=#kf%Y_hZnUtVGE)YO+2VhInh1YD3g+B#mHdTFLFsHiNlgjK^Yn)>B>^`+5=H`wdO*Ml^@$Sd?cAuMMK7D! zA}p%|dHuGZ(`{N5mkx;>NJOc1aFh)(!hS-68BRwq!GhOvpEyrzK=Y1f8(-kNXp<|d z__Z5$P5g<;=8j9DXF@VP$0pHpdLliucu(<|TKS_Po^kwUPRHm zhBB#!>Oi~b?(P8gDx}uX|O2{_XeYTff-sNMHbvYiT;g~t`$A^Nq4VS z^Vsxz?z?*~w-(qjJ^$|eWXNLCk|L>R`BArlY<{jY#x}&}^}4@cb}zEXw*g9OU}n&o z?FAb{nvlIRI!Y%cWv`)ELbfB?fNMVBiB}9f4LaOjm0bYDm4kXWcle`)2M%+)VwS=_ zY6h&q-ehlz$QF4bJ5ajFQC;5AiMzdeyp{B4t%=BLzIzO5~liqrGY|Yw<4REPDBl_j3OH z5^cgW4@$axG$Yn5h1+ zVWOcKj_7*>6Afo@In7nrRb<|7SvypnWj4&RWHzp~D0LHY{n-b0FWt0P=Rfacl97+? zebAE@~|Hc=ZG1nc>!^jz;Yay;uzl%IY#U3%y;G4y#Xk>;{qS|S%kiN&yHKCa{`&7g5&lb7$z!mFZ& zJ{);EojmV_SUm-AO{Cyk(Q#g&FqrKqWY2zrm5orkUfGzU+jOnA67AOe$I(cI>R-hS zfc07*u2pMkz0x8~yO`YI?KUBbSAeygDt8DDwNjUQFjQ}4yxyYA=_bh$v@{vePV`=A zqh_S~teL$FT|d13EW!fR^9Qj2L0$H>8(aor^jux~xnROX40RW*$m7m&M8}dKN^o_X z8@1{aE3*d%N5s;Meq#Z3XhxxpRL!VlCAE?&5xT%HRiXp@nI4&E*IiYl-U^~*sCrNv zA#Xw!mw9$=7g~nmK16XJx`Mc3KTwwQGlOkaa5^!EHMPR_&s6XMB+zM5x*op7GJthku4C2MtYAgV-;r5;jHiu&vpYVo__= zLx%dy{`F=kn|$kGv@>|L)^8m)((MwYD8Fu`bx$f^o2}pa4t%@bK?TFBfX2zXA!mOM zoGm3Qd}@Qe{wXUG$ioH_bQnZjPV6hRqW3fy_(d4o$z3npzu^$yk6IU}MuWo$WfXS| zSZeSxtQ!uI+c2fe>{)LHbH(b}V(zIY!HIOYbq@>_E5u?ewSMi6bDs6*)F50XHl-^K z?>WhM+?VEApQfCr?<0`0Sz9fo)-B`k)j?l%^p$VJ=WFzNl0Ltd?AemG?s?C83z*LW zbT0&e;M;sAZ1W)4=E1Pdk+98vCjst*(d#R~**FNUaWGtCBwV9%-nMq+S?kwOV>Zuv z8^TayHb1lO>AbXdJ1@Sq#hG5DgJXwk-9W+~>e!{YpF@Saa68B?kWmHav=w@mP_D$5(Rj z_?iQc4J+~3vZkVoVD{9~4KQ-G0uIas<-=sO2KbZ>y-{GR{pAYxMW7@+*12Nj8q!d2Pj3x zrIc|gm9Lb_R|*vHUjQ$Z1&9DkX+JRGY{|8PAAdX=*Kcf@D=kxkp2|j_FvG2&__r=)Drp=p}fQ>ljTA8J%1L=DFsK0*um@YK=TEC_02F9}}x zhJ)7OF-n6?c|S1epa8Lc-e7iSwWxf|A@oS5M;bkH=;5HpN_wmjRUGP0I_e3p_`_?# zx?96}QXfkabq%0OLo)gm{MMc9sU1gS;7guO){bzvhJQ~jAG5=@#^j^=#g}}hr`AZm zW;e=Ub?)*1+4ZgZap1ZGk0a7p64dVO9{7qsIb6PFIW_!MS;u*obqT;W+~ zvzs`J$l;a)*bA{rZl}n`44A~R>n4HsH!a;c#!~rCcOFSrh3!1LEhX45-Gh6YJo!1kHhS?je7z6GZ{nq(7+p;l!OM&08Z9WdbDIfRCO_fd3=lsdq(JKFF z0(DIp$74@FHwD2~Be4@ZHFj3muEtq(?d%hMkw%EjK}$5UGs2rPcQ3WDb;utq zaZ31xI@in|Lon4Yhnvo~ywY%|n&x1$tRy%n1}Eh-_#UjpIKV$L3U>^vGKTm^D>&l? z+eu>c48upUU?g!q#875JL{@|cu^3nn!VwG}O5%Osp;%AT7T=7VAJD2|y|U3}kk?df zj88WG;3{bZ9M_U#2pr?#fT4ndB(%#NYM~K>;0EHrEW}OU>~^2?o zHi&cLKhdqXfiahpsG5=52El;3#ylX|xeP-EJdfZKu&2aZAOm9Mx-; z2Y~9BiU$O$iEwaKt#FJdM>JhnfkNMens%?TsT+(eg*)R}!!;qPJ)JBTQptFdFD_XK zD=B5WpAbBN@G;T7ZcvD;+^HH@AWdCLLcYoNtJF0XrN3Xw1dMc?2#}1KXV!ntlfK@w z>{*){>n^Y;-!$sv{bhO#8H^Kl6twAB+;Bin4cN905=~IJCf>Mf^{gDGUs`C(h zL-6ZK!LKIMpuBs#^U(J+0Qd^z17D$b)gR z5W(+ZjuLm8xO5B4?%8Fq6$TS#p!)*(<&>|wI>o%O5V^;*9el`z+HfZ|b+-C_gH0N@ zN{vg@@reP~zrvB3YhG*0%r&kzx#A#eS?(JgKPe)9j_q=hc`t@opb@m66oZT9W4R#I z$TMyxK6`Iax?Zp>^`-P`tVC!0!zDM7|LRL`pKE??ORR6IKr1=#>E0!qgxh%zd_ zgWV%Q(nLXh%l|IMe7F`+`XfYm$MHhZYyrN00O{=AE?wCUOg=@d)WCU)sM3U>$-Es2 z>l2lRM5RA*Z5#Nb0_-#xr}aTZN8uefY!OVwoQ2IQSIVK0C=u9bP^7<(l#;WC6H#UegjyFAv zfjn9ak?eKL+^A z>-|pESe4Tb(I(w7fR4@OJgZ5f6F|q$7kyXhEs`gya-S=vtOaqM?CLS0<{nNBKWHFX2qLbci1mJ^No9&WSyhRIQ;c!|3eD0a(hY#IY$63_ z206c72=~F~Efb3#lyx7p`i&3XLcqm=fopxTKb+KZ+0@G-QfE=ZbUe7rWn{nWA1H3ZWu)GIOX%Anzzn9>jEf5Ssd9@r zUA=@$k!AShTc@y2qYYGLV2f0O7qr%LTTit%wVqb8 zH~y3>sAM6fCvGJwY0uT9k(_~V5p%Tv^{1dutCPoag)DhgDtSw3s zt>f?-Bci?{qP|3NZl^d@1L3@y#|_GhH6gD%eg9&8{53gTA72`Gaec&%yYl)tIjBA+ za~#(Yj$^1kZW#B^*2l(cuCzY9*9^*wK{KA}Llnw`KxWhm#mhn^kqWi4nArKTAf1=*r}IgOTxy+|umgGE-H3lL&Js1J)A6lR>ta(g54eEC zNk{fQMf0*eKAX&AZYnOdp52!{4b`?K77P)rAnkzV;|~FsA^;wgT|ejj#`~q#x>|iU z3~)kNnLW*dWUmwaYQR5ZUDg-@qV+=`B9HYV1V`4K+<~ZLck}lf%d}`a(=b&#U4{}O z6>3NY0@fGnH^->;yAXnj$iWV!(mJv$9iMFcb>hCAZ2Hp4lUz_jpH30kuOnjhr4EW^ z!U9s_E3yY)3Se#1C=Ab>WCt_cfEAe{(UrK-?(`b9LFt%zZ{rMTUa$Nayl0yeiC`H* z+g2l?*f7V|&&@B-$gk*s^m`_o{QDJ<>4WTavJ^<-*#`h=@8&>*>Cx;e`0k`7eqmr1CvHqi12jkX!Ibz6*`Ix@%27d-#b1Nkq|^3Ov4$lKyX=4O^m zApB7GJE3D&(L#)!8<4n}oN6FKZ7t#QYHKoATRYp2=%VP0iq!Miqt)kIbe>AX*xPUir5df0lE-8< znH;3tuGsWrL-?jF%vbS6*?Y;#>b5Y|Ykj+UjE zA8Y@*nWg9Q^{BZ0i{^H{vR5J|NIk&umg~9=6Al3mWoWkYTV2{)Xpauh;1vr|Tw(|8)yHYEprpz<{d^}}h)E?Q4oKdgMsTKOd^Zb#Q$cv0!P7SeYu z0|^K3$|i{Lcs_$VQrB~o+}qmM()x^!I-flHXj}>^v%i*n-)`l8QT?^P_7>m2*PoW; zhR4qnBQG95^GE)p@za0N_}PS*IDSlxo<`&6{*jj*KmAuWem*xC8oNFoy+=$RwEtT~ z)XAiJ#cKfd1zACcY#Gzmb7Vq`l%z&uXNcJ=R&5OF750HD!X4f639%9cLxKbUXs$Cg zY+yaAf@&ZlXUZ1&1mClZ*fq2?WaOD8BQ3wQ#TTku#XMXvF4)Y^5d(}A(KGaLjk33? z`#j&OCKg~b^4M(7$N;@p3#Co@BlT61#&aun_nWI=i#!@mC1{dkabU98oYU2dWTd=q z2D#Ja#|PFpzT>sH=NOgyjp&`vQ|-)3@it{by^||4zDw`n6&cldt3LTlH5Ig3T3YjMt^!}9(ChY^Z_(?vno4?QRb+f$ z1M&k6$a7Hw$RDE!2-X=7MI2f49eP=6s_12^*@l;Uj@jWd4^(imyTt6b1;1`YDF=K( zz!algT~=>sWFzOWy0NRH#HA6*AW1E(l5)1JaL@2hqZOVOPZYsp{I&xkkpNpSCSzbJ zkAi=}u9L_SglEsL06C8NZ})&o*xXCk0p)WRYcVXDnxMYyzfQ%~;Rn^ajL%DEPmVD+ zV+J(w8r*S!z;C8M=1w3O4)%4RPz)F#w#lXXM6GE9B%a?rheLx!$^;#{UIPe8F0w(P z&F(aASkE%834*8cnd9ZS%BJ1pp$eLhZ~ye5fmC0&#cYk9vn?inYhJ(gC7hM86$%|! zOGI$~w!D52Mpr>-RoNu}F)LXzW(|>lODwzkIYFIYzktZ3Z83B@htA(<5ls2pV*F>x zld4#yTfBkPR5HOd-$Lg4U`cQmPO?Ph=WMfK_n}a&pjO^`ML!_G^+)1S}@B;F} z*&SNp@&`%>0Qp_(&>;mt9lpD!;uH9ys)4dWxmL%qjhIr%A~8;$Whjjl59hpOTV~_B z8(}`s#!cte6jiw!N?Mphn{ zpY#teV%PIiNK73?v#dP`XE{052Hwr>UI+cyf`kwyt!ZqJQ=^O2e!m5ki|7y>t1(nD z0hFJT^9fx2ZJslhF>Lh!)<5K`f)oG@(kl?4=sbD<=JL&{8c( z7C~hzUNqQVpt@(@hfmoz=yNfBDnb0F6C^g5J1Hd>b3u^UH4;4sN2DI5P1d5<(eT*K zie1~cZ;aTrrK4U3?P*7gJ?*8NH-5$!$-hg@n;gfbCvLqv7x&PbX^qGJ2xpYA)%SkiWWxvFsInJP<4{uP8&!zYxP*xf z1!TO{Aml|{M9!v@eQ*}PfS!*z=y`A&M?EFuqOAr3>_L!1!Rc$@#Gx|bC2=oW2;4k?eVKclBMMDIG%$W z9+}St;Vd^bB&%o7f)&9lL=)9ZBQ%B?wjsq=3vqn}gg?)ZprmMD_$EN{V*_A1)X;di z?GQS;8&Dz3!XUqf4~7AW189Ssh%*fAuJHaEr`?^H?T3psW+>J}%$lR?qjaopc!+lR z*hT{g6GM@DVbYmx##^B&SP9aAE3>RXM~U4!l>LCBkM|$M73)XXPHe8wd_?gZ z*T;Ky2mAZ`l{zC%{MJ8Jj-PZ0!{jcZUo^(6H0tr8EiZ?u;9?@9GYL^>f%z7yF*=@` zV10gCDQ)*lGpC|c)J5S!G5>qk=V4?C7S@PaH&m2$7wtK)I0^ZTuvdyr7kIqJ6lO*_ zn!v6dfsM!>nw`M#g$=QIFPO-G1rzy|*T^SsCHey1W4+>?x<kFM)xs~1rrL(>PxM~=kPvz#=5j0?!5@_K+5`xPO339X~p?Zklgy< z@3_ioKPuX=?~L`v(?F`bwsWYVmfug$aaDSC*4c*$KU*iysfAeK$=qGsh<_U(?<2o7 z_?_Y36Q@*n@bHh|etL(%|6RoE$G?x#Azq7?uBX(R&<(#=F?->&7N1Q(ycYj@{2NNG zBWDY4Hb$~mi-b;d2W3~+s6&0!5}F$dl=DHUq~d&k40^J1zh>H{j?`r_YWKUeMY-`_WaqZsM1Z>ruBcq~l7@ zb)PSVi7cdU;|OYP(aY-NmM}ihLC@tnT(bt z!*K{1(3ZTG@ZBL0{UzCVsIOWBH2R00l5Z!;kw57o{bMbB+NstL-fm)(h>yYEuI;Y+ zB7F6d5g(_!>vF)+_+;oQ+P8NdL`m5kx;z7d+-av^%UX)+{wrX2`ge5s5!m$>V_6T{mHnnty{b1@L;N$EI!Kk>p)q6Bs>T=dMcAKgdy(`F+I~yV?y7t6%#qAm8GPFNsOcq?Q>-`Pyv6IX>4#|P{4tv2 z?b=Y5)t8H(+}d;{VDtb}J-|{cf02i7355=ABK;H*{# zsqY@`#8B^O4bV)|`bm4MkL;9G9M_Rj(Y`IEnAf6PSEoe#z)1z+6J5jW`KYM_K!sbK zW#o)Y&a#vY?NQ{ToE!?`J-7v`c+vP&hgyH$7+c#Ji*KXblF~LgMcF&_DN2t}A87wA=zQ_ou{`gD% zq->GbiZI|C37&jy2yh|?tXvq2Q^eoo(An~VOxjJB+pd%(fJsKBJ5q}uc2ie=<&g;N+-~4vOGD z@t(f&_@~h|$p#arYiz+w=$bR1N!Pse&(Jl2;{$Y!?ww2N8rwSqbj_OM19VOK@lT^` zKqCoQ&6lHb5CvY|E1`3CAHPyMCsg66=zmP-v>Ycorz=e7Aaa<_X@+}`IZWqxk4Mru zqd%3-8FD3bPOk2srgORkog?N#KA&nk-DD+u6Y+$cMG{ms3wDvQfpQYhk%30f2srZM zmENnZ-+fz0a-IFW$%k#ZTXMkI$D~?l0x~_co0&;UfXiC-h@J$&C(_YqU3$3P^E*PH zGeuAux!==?Anh}S2jN%}kC8=Q#LiZjRa&gDA<}Iec7_0ugJ5Ep9K;R`iHuYm#EooU z&f0Yz8mWQyXa~k?m`w~`ZWw;oGXt6UYg!pbbbDeKN{8IWSSufbgNl@^ums6Yd8aDO zAdQ~#Yb2J2a6AYC5NOx=>i}pr0lEr~dE~Icv6vh&mtv~_Y)r9rDrD;nq@!>xwbX1R zi_%?E?9YZ0%cgKBWLyXHQu{S4N}9sVIw#DAf`w2v6Z{@FVIIXW6W`eS{QO}x0f=}e zG!_~AK*bcZ|=$uKz&B(wP&ob9cP+FMvP&jQ>* z!G-2W{U;hC@2P-ghG3BpqQ}*O^Wnm!6CK()|Ah_Ul!>GNFlsLDKY^Esz^^K3fkOnk zakieG9pv^LrRO6p^xXbBJ^$ED&lmR#lK{Q^h5KzQQ~sKNQO{6g(zx}JRT%6_T~r{tSI#W zqS>btH1OXL{|G#U&ZfMN4JST{V5JJqCJB%S@i0u_VK`m-mqx=Vj}uCx6NJRxIY>33 zB+ON_dowMstVE}muFp|=r>s5g$;BpW_y#DmFJ12QRLrL9!G{%R!X(**T3lm<5*lAw zh4|s3CW>q33f*S*E1|x_z1(S}xc>GCZayTs<~guie7N${$6gJ2?G|1(UnDo!;_9#; zUfR>0nP*v>ZvDM%A@0u{e>{`t3JWPt_CTiK{3keFW++ng$+S`wzttbd9wUaIj;@Ru zV9YDT(wc%wbm>AVwu<&m1e2R9^9o&L2YZKfirmpiSvI>1{H`24xC`vRAQuwBL`)@l zZo-4RT=DGPP{`xt`7j>b1$NV`B1GV!X-juKL3K6`*Y|BjGplJBYSk!vEa%vAao%P% zX?x>|u;TQh2o-3@fY$VMO=Wr!d;b(~WmLhn@Js6=zawG4IHxlVfv#Kwl%eRvq)V;$ zkAe#t)cObwYJ`szI@Z>zB@yzydVf!-yDut&x_1jSawUkEbPefDN_+9Ufi-;~L& zSs@sCMzzjA*Qx1T_w;Kz*JDFE*P>9wIv(an*n8w;&>(|oGZlhQO-SHm$y}p(uo^Ts22>IPzlzyyr5G8YfcmySL@MbYYl7P7HX!(-53bBt2q`;C3BRf zD7u^d@(m0H(ls>%^G<{!4=9X=<0XHLc>GIA*{z%7e>}uaAIWK_6PMT_ghGu?Qw{7T zRJXqn(ldPcubL93ipIbVNzw4TOOLo@{%{)f^GNJIj1&b4;X@4gCh7koMY9ej&8HSQaL9s=n>pB& zFYpa^X0HS?acN*kH0kY*P@~a5qkvbm>yxE{Yolo~7_4tR#3@!y|4mM|1;r%F_*$Xv z8%yPJvZ35M*_*S(IWWF97yz7P5_p=y!LuKRy6%`*?!RAcsGl>jLSdMTX!8_Z}VL|Gr@o=K>dh7kyIA9!hRcd05s@);0fxNzoc(W3pDA{(SWt>n5hYurG(4t z&kYj4&(kIl3?58aY3du$=vV6psq=TwHc!+`u}*fFkN{mYjD7JVq8vGM;6U)7k=JKX zeqpIL7s>YbLk<3ubHFND$IM~C{x4Q_Z_LY_PW^0MHh{hXq=4MTc#WqCMeY@{am+N( zb_&bI`FUCY81^#_`qOv|= z+%VoMCw1qn#2SPh!#G5D=|RSiqIAVLHrH6hhLRgy>`_5B|49&`7$t1Q7Z8H(`#$f! zZ_ZFHy!+PA9zIb=1eTK>Ig3$Cb4iq#I|e2`)X_-O$QuCls+O{^0-398gQi6_8v#Rn!~bA0gOxAP3BwMXn)12xO+>zz5=Cb55)aL|mIzz6CZ- zZ&cSC{q|5AdpD&5wsV}6ZjG6phdPQ#G>m1Rp{lu2jFEEEBp-@_q3om+5uZRN4+GGt zR5%=ADZ>jD7*_ajMVP{UN}NaJ`T`qi0FQhowEEv3GidOF-Y5tJujtsrQcB4+5C~%J z?hwS@=!+m06rfHM(bb?d0f}41c_>XlA*hfYJdK`uC0U({*0O4$teoMjJfW;yA~Sf! zMZxQefIb=m`X~X_hk?$B9?&Mj>P=8pJ^Y{5Un%5UqaziH_?XId-6jT3gKow#&hv6_ zrACCK*kx+SDL|c&FRspA&0kyBB0J1RG|G0&Gw^O`4j-R5DKvKig4nqZ7==}PTt*ze zKqN#wiTH>xFqM(^Xj8-PXAV0Ya?WNAnsfI`105~=8+F!{fdZK>r>z7V zmndpDlAr;55hS7@DkBb8Q^e%-z&xEaF}QvnyOSn?IrEA$x&D$ApY8oVUUAAs*yqGB zUvoQ}kLwZ7BPl9;I_JU%r!Z;|kBIMUoeoxeTH6YZq)ClJ*eQ598R@E*2vQ?7ZHE&k zIhdQ$^+H7u>p)Q62p#B;{SuGh!u7IGBNTadm8~++vcML6h}c}EP##Sd0z^iYh_#4S ze@IlIw@CB+8c!+@ABeUbK1KdF%cztv;m!Gm?9LCxbtcE0!lXdYu`$63ALAf)15q0+ z=O~nKI66*3IMKmc0=%H&l)1Fge_t5cPXZj-yFS=*A(-=^J~TyITt*t=7{=j)VL@>)>`Ma^77wXpeWoL2H8m-OC=?P7y{FK^UR4Rf)YAHDl{LFJi<~2mg@ma83-C|DPu64 z!N*Pu#Ys3P8PM+o?Uu2|yva%m_N)-S8pqA_k^!WPS|1jUu&;r0K?g49_d$EV(7~SJ zT>3to3xu%tisiWw6?zS&slhF!Q_|8(vtO}UADo41;A&6jxHzzpq=t;UryM%N1(_qp z>OSHpl)2n9AmX(`=-O0KXIr17J7cwVD92}#0JRx`9@EMjOt#wNCPN)$qKA;qhxl=3 z0plIO+h`_nGLjvI$8khr5c}4V(0I21-Ut7q?za#|iC;zHrHR1m2tF<#;_HYI zz?&jBQ)GxU&a3b33=&_B^9qu$U;{Q2z0kh8mL<9UatX>s8Z8Jp&Pm2G#t5WP9wh?Gu&P_ zx)Y{JJI2ML1~u4-?3DmQt+Ix{7xz+q(*gC#lqK5Ec>#|7hE&dM_v%yo(V{43R@KU> zCQ3M&I}Bb_VtUn@=_cErzd@EZ=@6{`#qPr)Ind))r7eoz4F~c0mVN`7z(iwzTua%Q z&syK}QekR%VQk0X`Q~-VvOx!IQVF|@vreii&o)sTOy&*)HA{L`buOXfOhq}U1_MaF zAMlO<-jQ*D=c9gTsu5MzNhSAk*m?~%raTUE$6O9Oo;wKgE4vHHvG^6Fqh`ARs4XPg z#{V_^shc(9{Vx3L;ii7w1Ncx(C8@gsUeuxLsjE}=@O*wnq^3<8)5d0R zO-)+cL`9p0frLe^f|>{_5to`r#u$u-MUm-$?tQbMwqN^o`M!Q%(KGM9`|dsW-0j@$ zoO8$UH12N(z>ivf#=+f75ED)3pc;v~Wuh+uC<8|U=b4P-QkM0T=$zE4E-*<+=C|M+ z%!i&m56Ai4>pe;kq4k_pf`|$9uwPafp8dTRB-TMM&VI6}*j0o;2;D08jN!?QsLUfs z((Cq6-&I%ge@JRmE0Usax{-fBfWmJ?vU|>di-^dDXE#=Mz)HTKTvo%u^1F=%UsaD# z5FNm8Evo#&1jMYL4RrCZ@&@r0P&VWFDRBq6W4Fqkx);wbyjLSqCnZ-4hnpN10jDVz z@0T@zPXN`|30$DIse+3bF@<%=H>kXyT`y~bN4=~rYR4@tTt2~2a!IXVMd#F#{n4Yv zRn&11;o_ZW$A@-Z#AoEInNUQ)LIiMq138lOcwPkVHE7vKs>D4|-$b9J0aUEN z#M6(VbOSn`k2)03u1h|w_lFa)g#Av!PSm%;BM>{ov`gtxqh?9-RRemBdD-a1VG0T# z$UEA`VxEJSb&Rb%!~`=gQ)i~^cZqdO|1+Ky!c%!F614e3N%@E4GdS9^y(|JXU0KnN z6LiMvu4PfEk57Q`6fhqq%&ov+yU)wG@YGVS`ZBP8f_JT-rctylqS3Gc1q+ISUU-cJ z%!^M^ccauMxlV>hyLMAn!W#IU#rf?f;$cJ}mra3O%N}lY>T9f99D(Omtz-U zqDaMA$BR>|=wS6;zk3)J=pdlsEsW=y8UdmSCU28CMVzsHx}l^E!I}GGLES7}Tj)pS zLU#oeXBtU6sX2C*o8k);J*<)1X~|2RKwAV!o2g}1JstDB!N}`1e)($nwP+iV9u>nu z6hjp&26rYA?4yM=gAN6>=VpK?^a6Hgzz&NI=Xe+(}{JYqtK!-2>s))!qRh02DWyd`> zUZLv2#nu;;{%~@L;;N!vHNUsPk{I+~b(zE1UGd9qLisJ8bi*58{=De*ZZWcxr8;UhN28`kb9g?DmLLI(l6hj@F8 z3UAl7h-?{4?cc{#b2SiC#nl^NqNds9A7(4%@=SNJcx|-R!Z4y`+9D~i#5uLLod$+w z_zX|>Lb2QKXCA9hqBb(m`uoidr#DZH!cs1toO!0=dft>)(af=Z!i~s8zXig>YBp~| zBc`^?c$2xx$DK+ikVxV^_}M7ShCxt^iGE3$(`m)JWutJn&+Bz`K)jF?S7v5QGbFiw z9CJK;0VKfiJ*|s^tY<;Gj%V=r+@dSN2=`A{TJv2m%zYUGF#3?-zu+tkdkBL0&P0IlR+6lc{7nG{7x zMPOb+JJI-9+|0}-T(iyM3j_TbvBTzt3Cb43fR1O9eEQMnI(&9(2sP4ZiGteTKO;Z< zch;N99sc#^f{woH&D9Kui7N1?H;L_zOG(-gu;1c)ot3*os+g!?Lp39jWr z7=oSfxDRGz`u#M=zNmvl#za<$uZ}+O&C$-Ol;D@>y$Nw{t z3~qmG5z{UKnfVymtLV8;TJbTLuhNt79Xo&SY9pf@NSL)q9LT|R1ngCab&xQDeTk$? z7VB}_Lhr06lNw%RW*~Pn%0hYl=3;IY9YnA)YcwkcmFim$eWM{qC`Z7 zAq~9>w5gNYffobWyP5E` z$bywC%SyN6IdzI)a?Vv+>TCn=!$=dAG1*4SO%i<83FZiN4vKKCy|JcM(g;A13l+bgpid z!^!V@+rWM|vft;~?ofj^q)Aq8JyDG)_O4IwCsohbA#PgKH| z$gM@)69sMT0+r3giSlfxd}iRV3J>br>{@-)`l48t6fB@@Cmhl@hfuN3Qp#;Ijz!)< z?ua`k0fn3mM!sl-&4ZXKSC zaHiM< zFF`~ji_@GT7V6>(H8v6l%d=y=9h<9xr0my?bbjRsk`fM*JwcvQ6xmR!G(y)kLc z?^UZW=|(~U0&NELX{K<8k(J~yQu)w2rq9s&Qw1MdpY{%|$bGia{o}y#)e?H$$XL@r zBV$Ly4aV0QiW`rw--TRWGprz z!lo`uh=B17M}ppwVDzeh+}4-7LH*82iWbYMyQY98tm6_u{k^1ocL1cI2GdYzI90R1 zb%vU}!+Dr7peCQn2Uq{7DV6B6q~qQF8~!-VAMNyz@_MNwo#9=X=~_rp>(Nh0G9q?0 zP6fYw)_W>A;x8W0KW!az5=G(#wM$8v;!>@N_R6T_6wl9^ z67)Kr)X^;JPs3=7-nt(54xdsx{xhZbrEhvyqlmpm&z`P(m4a z_Tou1kYZSklRwe0v!59a<7FPztYdldnv8$7zk=VoNm9 z<+3^FxO~npG3`LoXksfplyZcqc!P`uw`F^nrKc$3K97`pJnX7?u|O7Ic!mR*f(kaF=E9!lIHe{z4z^rdM3Xppv<7vNV1UI7*jw+U~zIL zZd2upxL3C1BFIdzSKbb<_;$GS&K6&hST}A|;CE*=hLmk`2c{j}3hLvyR(vc8cYj3v z#8DWP<0u@41-iM?Sx6iuUHS~EwvpKnve=vIWdSyUF(&7ns0@e{V3eTdnys-HNGgs> z*j-d`9&ygwM)9fSO@_J0j8g?WoEe&h_0=85Xrx5l-u>)e{I-sz7 zG+RL=WUkRo-?Q{hH4;hVPYsQPqi z3}vY@)5iwhSsN&%7J=yy&CgbHdEJ51)H?5yT&P9O*SKlrV?>vafI-hZ15Gb?KEpDM zSl?&rJIT@*C-Z@{Oo())mJqo02%bMs`kLNuCUj#tI(6=#1p)H>#&k3?nidaw6PngL z1U*))e47ds5>?d`B>P|Glsw2r7 zGNpUgr=)oh%ES}}x)HRz3@Sfr*)OQxQ&upd>ei04-D~f@)i$rVn^6^8+|9^}EAD1= zO)Bmt!rUW@yBSfVin|$A#^P>9R)63Ox9kV^O4ApgTJNEfu9g>H*3roUFQ()`YVU*o z!@j`FmdJV+)ERPM3UgFCOsW1zl_M(AZgVWP!gn$I8@rtmcjNQ~--VOe&Y7yk0mfK8 zkqvCI$<;2>rFTFER^DP$M$8wDR}dgWzQtrTU%r1IIyDDr$f5CO1ax9)?VpjFo}4Uw z!or!@Z7wIw7%{P7BwhRzybR6b1kjVB<6%a)SRG(qR*z3ZeF~_?e1mlFr+&#T_e`4n zWI(ebELEy!Ht@TE+5;_BBQ&-pZ1l-yK_e}_`Tb)$of=Czwf=GCto74XN!irWni#Ws zLm}V0Z68A}pZPVeA`0D0TMG7>MgUzuaj&e@b_lEj+fq7a>=r+^iIz^=SbI&6y%4jt zfh=@*uEHNa(|#U{J`IY$1sC08-+-#hpWiq^XB&ZKSPzO2@%+|Z5f6#zV1AcwyZ0+O zYu*S@awe^JCWkq=k3u4evuSY_!7XDl6%86UC)s7SIED0ZvpjA0syst!)I6DRAKL$q z*!~BK6@-FtZz9~EJr$__p}Qe^BSZfWs&yn8J(D;dU)~dGRz86y>7&SCL8M&@vW1Y} z0Gg>+=z$)O2>vkght6MIkA~MlY8mWHudcJWYzFj{xMU45zy`2OxC9)2;Y0P`5Izj| z^wBsc>~HAl$4EasX(<9bRTv(sbH^`#oXTbwR?1}MziCv~KDxK?OA(w;x7gCTKFT)P zImbg;xS3^c9Q_JbOc{H_Y&Y3^4OrjzMiky@?;W)Md+G9(g&OxXNk`jeO+ZTI}E~$ z3cggZT>p+XM3H(mn4~{^ApJDgZNMcJz#hgoLZHu>h#Ane-2o+~qjDsSc;5Rerh=SY z7>bNSlOTocI&S9C*K(o)y0N#Dm?wKf@0Z8?eto+&;{&PU@st#tkD(!?iH~X=D@JQ* zy;i2^vuQ93N>KUw48u;H!?}*#3c(GS;KxKigXyOqeyAI%g%!EDaV&QLL|6MmolWCb zq1;k1dBP6mZBmAz0eSsRSH&JNS=C6QL=QmnjNn!C#xKu?c^^xb?};|%gnUl5=PW3*lSoiYbw-;b=Xgu zNSYITyDnRLZWXffmn`x0!fO9PZgUTeg5WgP-!ZqqW^%69J$Q?b@xiR>EgE>J+@!{+ zMd!|{##GPVs!~_}!zGI1G&yHswVmwAhf=e`TPS0x2$JyyV8l1QbCwAqc!t+u5{P(^ zyr4+5hQWv>ow&;Kc?($nn3h>l>9{lla+*dQsFID4S!8}6crv61wQO?d3ffF`V znK=_F6H9Z%%k-7XlPi6t5@-QDUA$;NJF=r%XB*UEH7ad%`Pp2i+jF+FZ8KY=W4?x> zA?^5y{KJ*D5`5^WRvJovfjlCf&QP)uu3YSEB8Z4H-(55uN4sqI$160L%iI;uv|n!m z6MX>lspj*?hu{=iTZw~S9Q{5y-<|05rT5$TC-)tJzCRuz`;O@2tK-MXZu!~V+A_p` zwzuu1f=E;uN}4!{Smf;Imbx>}mbCWf^Tn667tQ=kI|ST@U5usSY_VgPnl|iP4fZ-?j>Fnv zX)L&1w6@3W!C6v=wH>VsGi>GDMybPkiOzv+x^QAsa5a8~11eg@G|}xJE%*dWX=L3d z%B?lyB7?c5p2grJM(HgrtB9)|)ka%?WX=SBWs-iveZPSsX-75~uV1C>dOd!&WJQ|` zRN%t~>MX9mm+>)3s^nUHxW^C!ZHLQf3&Y#TWad6(frd6b^z=@a>+Oje6*fh<$8+2R zAvE0MS?;0haOt?mM($z6oSCZ{xLRRX)tsQSw;CrU=-@2|sVik4o!6&Pl6^E@AD5(- zy;S5C1W%WwWnR(M@R5#CEjExMa4^2v=jn|dRT{WSHBqmFZm`!4WnrV&t?H;U*@EB> zSpd?!?RYY8$2aqKOp}3ID7a4T9!0b$?XA6Z=aAApKz_X%R_$)5Af_I|qGni35SNmp z-^{+9cHbn2|I%Kkafit-ZhIZJ;@M@v5w4S3v#$7LD`Z?I=@?lidx1$|yNwVmF`a~n zM6&|!<^@LfbqPhw8fIUzi<3lg#Dpc@AWP`0 zx@AGK)T?4TWV8>V!1RALro{}KZi^ATeQYnebmY21E)BUl$)zIKH{^n1fqm==QMuc5 zk@|(2bfYJ;2@U;(<3|`@+>Z*{Z4!gVc+knhshAx>ZX>;S(z^y<&yN};DsiG|Zw)3K zLnwL(MZam(AXrEVimnQ0_mPEgrb3CS%(edbBn9xRP+mA!bb zjgqw3qTzO;Fh%RCzzZ`y(1qPezVd(9f{5_H7b=5`N5$5qG-S zWg&DS^YSm6KO&ZOq7@u~IGS=+hqa$k7^$vzz`parCxYztO1RVq?yhgBHrB3*|&TER#GW&1m zN!Wfd%8rZ@d53PW9>Y$CZHxh!F^D@I6wY;06IPewNb2>E>BR+llA}VU3c;kbj3J$S zVLyYNG^sGA=ZH!Dc6Y5Oy7%N*_6V9>wOiUv1w(KBJ7LEG#0Yecw+3^ZKl^V5YboeC zcFORvwZ~^W?3c|2bgqm9I~#MNlX{}9`W!}7SM$oQfRN}eST7KR3_UiX0b|s$te#&I zHzfOu+@~e$(l7A>E=ysK%RaT%J>8Zjyn!z@yXk|MgkORvp3rNRyzxomMet~SS6q>Yrcy> zK+IbM?J^Cgh?}|Hh{uibXUMu_2&_y=pp{>qhGkv_EoIKzMp)tv8n4 z+b7oEK+AtrhIDs0*Iz%*Pp^hcOSk*2KH;o!+4g^4_n$2i7~+f(f9^8NDrl@n-EF`|67a$?b`D`nPmRMcN1RIaKFAL-b_J&XKK zOK;WDo?X)EoVa0$1-C(*1Vv`CzHG2h2Hsp1l0#vvsbu`0r8kd}yU!h!tIS};WCnb^ z4Igoct#x9j8M|st2!J}rKD$sREqAlMHQ=Wmdlf>Wt-P9&jIap0(G%G!Z{~l&gs9$$ z5uO*V`_!EdVN0C#Rl`#aY~lP_sBkAN%%y^#A9h+_#T3A4J=`}w$&cC#UR4^N+6%$Pst>6fMLnz0a*cUb+3e7XsCl$H%ZYWZXs7DV zqJlaFaJW+u>4G=XHBor@zqt2{Y1^n0vQDFqdRvL?ESj&Jpqb;|CNmG~o3UAS*k`tW zV1JeGGvmx$c$3Vkb(#PC)?06ZWk~5ud|Nju>^Re0iCa&$Qh%aTb9F6Qh3U$lZrC|8 zReEI@cuJ0?S{QGiqfyzfgbI6YCkMZ*}IUPy{ z=d-#Hu40-d_S(-*cX@&y?EvHXkmY3E?c)^%Q>9i6+2V}(UaJ%R{GV?Df2PHY?BlWB z9_5LAnN<;49CE8j%T!LVLLULX6!)OV(^opmC8kB#PfmAr1wC3HOG`t!wF2S*Nt7T7qzW5<|I=A=W7w=J!5}O(-1bb%bYJ$S&;5gZ7y<%z4 zJL4>+5RN2cOuLie!M1BU_e{?4HYpgaV&9b5RjJ7vj8sJ=MTqk@`$|wv)mF_$F}*{*Lf+ z;2DZ(M?Q0L08X@HJ$mDeUb-fu?L4E;+%TiNviup1qKpblZ;(-=Kcne#HmQM$y*#54 zj#5fQy$3AQNy$^=zHDj4{i)Pnw_jp8NX7{jcE?8tV5uH;VxhjcnA?HRWIn}w48N0e z5%C-qS9MAd2e})R>3)dB&T_PCj z6*Zgv(}73QrH|CK>^|Ue6r79Quy3h>_Tks zY$lWvt##i*o00`*(xoCwpjt}fait}Gbep!a*~N96?|hy!p4t={_2_XVwR7o=(s~-i zxLmWOkr5j3lsAFra)fO!DrrK+EHY8PyJ8)$)>B-Uu9rVfQJ}oA7VJ8LiBhLJc;Eh(pN7V>Pi^5yw z{Ys^<0@3BTUm$6BmH&Nb58nUie?NU0@2`vVjZw~mCLjVA$W?6JO6KSgC^f~~7KIS+ zXwu{qnvgM!8!|aoi6j|u>Wdb8YpyoiQX>qOw*S^wRWHKnxV`Na5-*V+#!F_~&)`Nj zcw;h-pMmnU++-Urt!J@@QLLqKqKev0BS{SiBFOwR17#hlbY7Jseu} z@Mm3)#h;fgK8iflLo|4CscT+4gm6SdWXBo{3!lJX$7r*!2V(c7S4g>kLq9@l%=qYmdjjjQ7sBPM~doX=mclwZ9bZ3k|h^ zBkm+-5UeYOGig+CJMaAluQcUvfHKp4h{@&mL|5Sk?pkv1r z5fhga`=gNXL1lm964iD}kN4eWB#!X8XWPr{uvW7NQYHGh7d)4LoD})*ruiso;B;FRKI5;oD^*X zk7lK4GsLIqAZS7_exRj<5aQF%!~HSgj;T$S1~RWr@|%`nBLvdrH&}o0?4bOyv$M?H zpasrfy$Tm*FwVm9#p`(?4HtuvTm&U&NS3M)&tsPUga?R$HT?A`xIyAvraOW#WSQ$% z_{hFhYwWcow+n>Awsh%f_y^3GxD~%a#oeuK8VD?*M?wCtnB>L4Q7TA~y^lpz2JO?VmJv;Iv<~3%IwZzG`I^BjCdRdChnBw zH$0QMMXPvb=C{usn#57bc9C0;;TCZg?fe_Ek;;u;#T_QHh&WSuQA`$NVTM%$k+TWu z4&1rf<6)Ak-(*Pph=H%yD>8*s#U5sf?I>iA=)1e|I_tNFlCPKofZn40WD~zu)bScM ziaAD$wodk0%Y7m&+I_OmGVT*)(Kg6FsoZCnMSEEGN#H&vi?&Jj`5yNf4GUVb&v5P& zYtgpLK4IKvszrNA_UV3=`OL6ryJVj)xzB8iwnz5)jQb>7w2GIwPc`?MZ_#RGpFfaK z-`v|W$(&b(jASE^qOoW{kbMfdkItg4lzmokpW7{3N%r|6_qo%eJtzAl1}22nC+9+t zH`hE{e3EYKwbZby!<%hJ9MRu|&~u$@G?|zhwxiOosUF&J%Ef`l?`cbJ&ahnIf0H?5 zbM?^XVb0~`e3qPyf#j;7Vc{VLLOep+^$I!PBu-sUTLN`qKR_v20a0YkrloU@s85jo?Sa|t;ozCwt{`{g5t z1hn(pNwBcyQG78(y zwChIvz!{-%-mSyB%+fft(sx3+cA)gTB;dV7*Ll_k?c0Z06L|S^Y=w{s&yd=nmKF?M zH9A~~4N;v=_)WSG6QXh05rX`;dzw%%COUE+&6h?IAL|5hD!gaGx z*M7uV;-$2%i}FdNaFGp&Yp7rZ4m_03{jwmTU(b!A3SfvLnCI zS&Z)p%TCKkIiC*8^!#J1GXYrP1{xhzf3ZSIVfXd@^J>5{5x_3n*mQRPscm>nm-Ckj z{FUQ|ab@}a!Je}DfMgFd(3ZW}hetjNpoZ3G{|3|M2zE@ko!F;ia~FO|ZrAalf?by_ zi~*}3B`tp0w_bk{_h|TJf;Zj6L_Dg&ACF-|cBHoS5)deu1qM}K(>%lP52*J$oEqQ~ zUFL%^HJzQ#$CY-E&hX4};*Km8%YMVtud(KJm*WKz<#f)Yoq%s0r8@e0VeKRlT6uoi zMO72l49%U&YcgV;*2XmlXJo_zq*qkNe2B#h&crmtx zGDHgc-7A)oSK~K^-}kC9LG7CfBf2JwA`N9ibWjJ>uvpx;Z{Wyu{#B0AcC}B8jB7FT z4;hk+hZ9R#xF()K@dcue7Y^MAXz5*Z7mjUAMcYG;Y>D0FsfrD$5BrSaw!;hwHi2Khm&0=GQ*hTB0{^gp1Wu%;L z8%HV#7a*0f-{%zyFTPekS6Yws1vPGchFp^HM~WJb1agyWW-C341@3YrA^j2Q=ic1* zBjiBVuvHXGmETF6}Ik#waMV<9ce z;hh^~NS^&ZYj&f@AjHTanoA&-|H!_+|Sof@opT~-ak)IiOq2Gx9OU_M6bLNoy0 zmr4oZ3{rX?Ng*McgM7)%9(2j|mXXSL6{L4x;%0wgL5K`HQo^NB|A>X$3&o;McC_T5 zyp5;1J|!iER26)YS9>Fuip+u#6JhwiKO^6>R3R6Co{dl>48No{*qe)OuX&XW?x_uC zxv15V*grg`GiF#IbGpdjwU-exDO#Hgw13*&KUeZxC-lBH8@NEm(n z{*H8@9?i7Aq|)%bOLX~VF|e7p=y_jzeg0?iCS0G3v$_Hdze=RJN(WAKMCgQEjxt%Q zReME1f^yKv>S+~9CUjmKkLcIVcYq`#Jr(f@Yh_eG}a6 zQ(NIyyZgc2HMQMP`Ypn{~l;5in z2bH_ZR|VasnyNB9^C2CdU&Wy~Ej*^Q8SL-iY1n~`wPLayXKl?7Vt3v^L4QXbs(JJEn*X-4%_* z1mDm+bu_!v7B=B>>|N_IuhAJw-$Dep0ydivm>Kqcgc*3N19Xvf#yer$u9D0(8guEx zW!O79wC8Q2+BQGlgNsMj6_8Q2_&Xravpy`x@VRW^7G{SgdY&A;`<$8x@>#lzfJ5iK zDs<2Ww!_4Na|#F*zoxay6%_AL1O1rzJ2XJOjc8~Eab%h;Aek1e34~Q6!f*u~K?pXS zf+5Hv9wgw-zF0`a;)Xn1@Qk9V=(U%!s)^m?s_}n0Z7MAvpG#f!9Oa_*S_k76f=zx10Jd+U+hg6#mc3j^Iy+P_|{xAf+P zh>1G&eoJ>==uCU%c*~(Yi5;+AZ*MHOcX=!}$Cl4{MQwcOH3j~X(eRM~V_B1|UFJ_o z1ni+V=#yiagdH$)Q9T=_b!}gH=bJQHTh3R-;M~Y#JzC1i5G6Y`C#V-u?a36p6z0F=R@$X6Km+HZgkIudl7ul z3n@%vTjR0DuNs@e>V-?47sYmjia-dMo9sNRZp`avLAbTLJc9*c*M!^~gAYStqS1T| zE*)I@&ZC`8Fp-N1_#v^G(#fteDgx-sNKeB-z}KA0g2=g6qztn(ok#6W3I{wLc*VzI z_!u!4-=h5AhB@#mXDx~l__Aj7Wi5)5q$kT-6AKCYC`_Zfv6*G<7_x@&2sMmlEy|a* z2svv;p0y}sXc)34XEN!D;Olbt1HtQ;mA#m9TGTxwKeDLXlpkbxx8cxN)nb+TU=dV+ zBvh68U^N?`?eVi;)*3P7TxIhz-P*N=9cg;8%5_S|%+bP}^Xg*?!=Pik34W0;K)Hq%`0DY(f(F7V|TraU;e zeTH*>T)SbWOZXZHD%#PQqiaD^CFoJe^zQcH@6ahE-W7dWh>*X|z>%(z{4kE4GkkDF zUFH4|nFq_P_k8<1+%4VNjP**nReu$4waVCFX2wP(*7hJFU;B~EE^jdo5J&6823PAf zWkz?=GdfTR(R)yCjVQIyzNO}FluJ%WB~@i~A2)p9BJ+TSM=|L!8munVRypveicLrW zD0Q7xYF0qyp;+fk*=x&$npg_=6x?A=8Dh2Tv@t!bNeuni)7x7J@t#ieUUj>=+kU}g zZ}*rFm}~4+8tix}mBqrSG4!wQ*gxTMPxj#@<$InXjG7kYaLzi{=Q0qWf~mY z;SlaO{4T494qDo$Zz;A-e_MlHIj|Md0I9Ejo5T=px4x~@Fwf_>r%}h=e#YNSMiOkR z_z8Qf*vKAidaC$u{w-LiRoDPO1^gPY8}K=x9S~HYRSW}sA21)V1ds=K8t^N?Zvndj zdjO{ZmjMF`wTdZ#Ie_~C4**sGehkMF1GWKn18M*V0cQXm0DTeS1EvDf0m}jF0A+wpfGvO>fIWcY00}^U;!oAa zz%m*BuG&~or8Yh@P2=-_^-Hz!#hDu8U+^t3tWtie<)=#a3zpwC^0y$_Un_?($lrBx zSiKxBOpen}4j&@N4VUAE$~Y7=_E?9`_uTi?58r#>^+%To)Du){wb}~`wcc>MdFu4a z>U{^=FZOs8{(rCmuEek6s!D#U@tiTPZs;cC5=$~PLYCw-=qZV*_i2o?0Sf>t0P6r7 z0b2kSfPCS>2bbmND;`<3X6cGY9x^S>dstYxY?Y1TJ|N`eEXy<59(&A`zjEn{74Skh z+p@e>OIMhd<>ft=r%*ijSYDp6+P3T=Q@$;4+0vC1CU4n~gk||Q)2hd8rbkw;Ua<@a z5kgLbLN2u}L%5a8Rz8;ZgbA1*dvK}kk;hh2zBKlgH;OZ z#7dO98a1LtEd-;sjEX45XvJ-cI~1{sX^L5jM8yvj3$WyVn(C|1KUJT9Y9AII{@pk& z`olfqtJ3FK%oE0s88vd)O+y9`ii{XIpg(l_4E@5x_4o@53kwYm4Pk#e`U_@%LD&3g z1O7CB>rZ{{pNg9LOE0}W9naR3ijU|y!)&geZf1XnrvKt4`fDctSLvB}^2ZUso7*P8 zw@trg(NC(r8-I!3i7C(E@h^U?RQ&(%|9}76f6D*E|KWca)biXRSe{pe$@2;Wpg&+B zAQCVbFa$7^=0bpxfKjwE0gM5R1Ka|L0niHndw@v*Ghi~{E0*D9DV2}Wq1+W6< z0_Fkk0VDx_07wC(0@45(fK0$bTA~9M1C|0F1kl+3FwG?Zj{<1Y@EG7nfP8=eSPOUp z@FbuBupUqhumef~B)`|ZU&HiHtmDZhR0ig-vDS+ ze=C5LPJa*h1AsRCw*z)6_(d*%0?_v8#{d_g8t^Hg7Elk^3-~kO0H6_Y2=E!;2%s5o z4A25N0XPXb4fqRyjw9LtZot=oZvYnn7XjY^Isx5)D*##|djMqpOAXKhf&n3bFhDrK z0O$`G2#5p>1`GiV1<=0nNWdsSG++#19N-o}3}6D_dw@v*Ghi~{E0*D7p2P6Py z0jz+zfO&v>07-x!08#*{fHXh`AQP|8=FO z?(0dSTZJ|Qco)zOn5Raa0=@&JXi#r}NG;k4pbd~2ggOCOgHdOI1Rd%OkQ9PC0X!0l zG6lR4hCJ(0ZvX+r4ey6K1w3IunHW(|fYtU=256O zz-P$Vhc}^34Mn>fhBk>#S2_Z1b|ktw;&Jk$jdb3X*%+jfIQAbUS}iE zR^)vy${-PCaW~3@E>%uK8QqJrN=BL8hq6mW8K$8u(@~}iP_{or881XxXQ9j&qwLXX zPd|J&HP8iMo3Xb%;t#%SW9GsN1!uV|3hbbX+Yuu5vw~7;ZcK zO7ZO(gmECOh&WEf{Rwb92V6e`&KH1t6Vmtv(s~(b{*|%ofNQGP;z?UZ*;BR*nTn!- zfXXT=8wFXi1Vr}Uv%M{QBZ!D12r4KFsDKO=usCo$#LtNvMa6~U{!pavpuYXy@Aq;E zZSPH*|2a7)xye7dt%I`b0mDAP(g>Ii0Jdhp*aBGF0P|76-T^Wk2U&VRrV}9BDUfjh zWMzZQXF>M!po5E`i_4&sE1;XJprh-ctDB&+QPABz(Ba$)pE1zsIOz5n==cTb`Zef$ z5_CWHtLqLP9coNN8XPMu{ItXhMOEQtilS zAdQUJhsh}KAsNYtQxIW8L2MQUO`N2l>8}(Z<+u<|;zB$el#%3kFb>h zn&=ilsfz^BK!YG+%L<{qDj_5zDU66JVfZY9CK^Q0^deEj=@CWPMhx-X7eg{};>e6& z0P94iWnDi1nvD;yJB= zWQyja0S`rlwUy8WRz|7!l+i$s3SxsJ<}p-}Ot2avoYfI~wFa6n)I`%dT8Oh~A*5e~ zc$R7-8KcF>Y|RqHa?wE(AxlvzYZ)@D(?zraJt$uv$p{%B&MHGhi!wqJ`&XdpM=KGb zXpC3^CWxoS6v<4Rp#fVO!VMN^;`?fp>a`XP3|JzzrZvcKgJh_7h+x_y_KX9Xpsz>M zWGBQa-GH#73*zZ?MKbH$k=f)%#47hh6Dz$zejj93>x*b^{-FN=Bs01Naq5E*Ejk2E zScIWzxd=pji~QMEH-nwdZEIrlf_)0X`+0Cq2|h#Hf@$D~8{u3c*j6>fGw}W^oYRMK zZw5x}5saFbk`T3?glLLjFGt9T>P$h+d|Ze&%7s{c+(_#b52D`UMOcsz;Q)R_y(@sU z5`+*-PXy6q#ZdD?2}BK^huD8eBU+>!q8iUf&F0F8O;<(uiw4qaS%j$jbP(%-9%5}W zLR2jiq-Ab_@Bu5t_H#hZG0yOv9*9=&2Ywuks7}$S*&-Ry_7I2_mXEX!mLsZn4Z?+u z2pb$l)Ga5Gmh=!}xm`!J1!Jf=a}rTgzausuA8hfI!BjCV+`M%KW}mXfxW*f6Ese%h zRwiauRAE-=VNB&`W37za7!SV1?8n@s<}pPQ_3R1~t=xsgc8DQSImM*rLx)H-w~Hhe z&r6clSt^-Yv51V5*O75*9GP0TgRJ$YkIV{vMyAONQJVRTDAZK}6m~}$g_hn&p;o`4 zG>a&3v0ty_!b>x`w4QcxQH3YDSlz1JtfxNQ)Y@uptrs`A@vs;Vd&35vX67~?>ZV&f zv=6ep>^1(pRG((vW{Z!!v>&EaR%J0&OXNP4nzEP=-(d1#?OS}*{KfoQQ@Q-Ch$s9s zE^~qA!94=hRxHT=OQ0Za;a>!)SM-INPwx?8^9c&$;~BzQ7v2g}9RfsH_IE{CBhI4K zMlxE;*KOkUZ_7j6(CFs|wVS!uf1hYekw3Rf*a;tkhh;U70Q8 zuYwmYU7&TJq)J_NN0sH&p|)+VzXlr>hBi}F5AGY>p}#1F`#@-$SHKNMz;leYcaV@G zn~andxX|I-+~@&`ig-Hs(ZyLIctoridNv}3bjlRavQ4V!yPq~{?O%>|G?*g~LkC1Y z=7pB8jzDJW1fo?{BD?D?h^~AAX$i0{d`{&{ynGWI*b+ z$sncnT_ElAl_%e9OD6m3+#~ykTTxzrI7LzLHs-QgeV&VI=fxc_Kf|pS+{_dGIDj|S zTARAckIXmu@g?8wn`8VtAH5J*{edKu_(eyUxE~|J+I?QM$Us-Tuf0C{i`gJY8MsIDq)_4d*TT(VgXV2mS-3G18%NNxd zuJBR2YMd8PWp2Y$yr$z~yLDicfWwh9yPS^g^>s^s=k2w4XQiLiF5aL!Ur&T*ooS6d zE;F7ypyI<&SOER51N6Jl$Nqp{D-IMOp_j>Iv~w>PS`PlaI7SdXekzWX&&Z?6ZcUU} zVT3%a9gxRmKWl9VVWJMg+t*s*3@ zv?b2m!#gT@wii>WE0TNoY}^kDa9tV`@(~XcU8dn6@kjeMsXldUxyI9pip|?KRqyPM z)cV}JK_~LU^W_aqD@^=p-fLU;_^mts)?=egsdqrAJR|y9*3AqK+>m2!q8nJTW zU9wmxoeNcD!JonJ;#ctJfDJUdHL#Ex9bcND04 z5le+{?%gkaAedJ}>j&L9{rH5JLb5`^k^03KTT9bX!E+hBqG}V#WZo#{ctA4svF3SE zWwO3fqIISb-QC@9!0QN!HLAh=HG7lb%h^^rqUf~&tNU4q6nQtBEx-|45tgGO^S0cM zm9nT#?=jUS#DyZF=}r-O>Om3N?F}2pd|~cj)Q)N|D1{CgE?~{n2(i!8CiLFkdY=@ zij2`Zv<3Zp;Qf7w{5&L)B;-(l9IEJl1W!l1wPr@kG*uKN#Q6SpGHQ#b%Q`FCO1;Gz zO0p6HzfLAa1^c);+F8<8E!WXhloF=Qon$1(g!p z-kQqN93nM7BFN9v#lZ^7TQVQFG}cv@6=czqV#2m;a(9{oy;$PH?{J=ds=K}Q;J&(@ zm8`jkyi35iJOZ^NKAeEx;&hTU`8+v?;>u;ft-+(kyOQd~SIqwx0Xd;m;b$VgV$a3X zCFP|qNoUL2$ji+CsCZlX?1EmkZjDn~LyJZiztiE<)zY^!h&I~3@}%(-Q(oHQ)sAbU zt%_{+*&TNnTz|o7$hqIO)qR^sw3mespYM6Ul+6lTx&v1Sp9wJt+a3Nn!aRx|-5N6z zJ0ABc{%OM1#G^@>$<`@2^+>8y+C*Ah`p5Lpj9VEi=#}(mbR9+K&ij$=dl5fbhIB`Ko9?;^0j^) za6Nr44IERTGdZk*e_#2x6zOn%>Sr20ybPOSYwU=BU-{P*a4drqkOmHS?2ChN1pa;H z-%>1t>+W-D;E2O1n1QqKFLatb|7Xw?mXcRgQB~K_TDVAi@e&=KWx9I$%MA<-SFBuR zY+`C=MzdJGX04@_m8OKU*3#uGOw29TTG`myuXEhs>h9s?y~%HLU~p)7L{v;%VsdJF z27{?7rJ-lM+Gf48yVoZFEkU8-(eX*C84OldUQuazW!27_J^PxPTiT9wERbJDTjvoF z9+$$%&Mzt7zH?9G;iH|seW!&oWPMi3N7u(7-col^=j;QsE5$o+uPoLFxN!wZzrc9jEsz&Ki|F8LUS&~ z?^L~PHoLpKrO;e`F2(OuBf!eD*_~w;nsX_Br(*w3Nz<51@jKODE?&HN>eSH^3r+Sv zg~7qWo}Shsn#Np;->EL1KY#w@$s@%UnsYymJWDvwekPh`CWz^8HwcI66GX$;8sf|6 zWWx57J+bG50`Yn31;g%LD`Vee1mpW_4Tj6Bd-T>9g>;??J$k^i(G2!@a>o28A{q3t z{ppV$>ZQ{joJ?!FXPPE(w=Xqr)FAc#t>zS~n^GyA*O|!+u02iKcGV(@GE$S6Iy{vy zb=fo_>{3DevkO<^0)_|j}ES1DLkZ0}lopweN@z_uqA_bcLQv*p-ay}a0T!&V8Ctg>CJ zdQ0c8{8&@mexFxwV-*T(V4WGC#8olbFyiGM#5h%%&NB z=JYoiro*&0v*D{H^ULQzrtPN!=AI9o%+FKfOuKi|tbLQttnaTYSuU^cuv%ZJW%5iU zWd=MO&SZ~kX3c*B{m9r<)}x2s*|Z14*-iJ><_O#!%!wOaoqPY*rCh6z^%G?z>;nd9r_--HE2k@t%t9%7-;t*E`{|AJM#ueaO&a^g58%D>&13Z*htBTVb@*`I z!~LRYZ5i_VJzrm9{4awsoAmUopRL zw!EZYy__?!VQT_AtL)8SZ)wokk0npe>6L6AN-2JN;Y?A;C9$G+mjervhxlEAWtGizlvv&`fRz~ZK|vJ}0um6eCH2UOPPc&ZNOd{SGTTdHv>S5?bB zuXo|gJbP_s{)5Hx1(7=a1v5(n3-feEibV7Wi>j6<7t0yymed-3ERkE;Q@V3iR++fT zhOLFBYURj$wmg=0zv7Wa|2F$IO_j&jR%}P9F5eEYG&4qh8|&?s&^Lb9_7w zDf#X?Z0z^2#noTEEo^h#k<@_GM{~A_x0eKlc9aF3=`0DJ-<2OibZ3N)_e6!+p703o zI7y3`-=`W`(oc%w4BU-MV7EoT8KlPqowbU6a!xRA^U!eI(+m0WA(u=N-d%p1kUU(I zNExw6s<=9yq;!p$+4Y&B8~Q7S^C3=`_t)T!q6Hf zWekjuX81qTgI2PTe)z>by7Mb_#`Nn5M#E$)!}i?-VRjZ;XAaSdX9-X8XM%@og6QDBLHP2XAo%!dh%WwQ!e7vy;1^aP zj*Glt_=vSKxFjMNEs`1xXQ_MiY3V|Gt*jp1Onx-ui9&KlmZC_8vhx1)0TsP;Pt}uY zpVUm#N;UdYRkaLKdlxpR*lSCrJXp+3j?{UYG_%wqDNna1QAB?#p=!Blf}CMNe67)y zIJuRAaXVL8$BLWKV+u{%qLKN%s8|{)>XC(Nr2QI;h~sNL!xgNe!kE^K&__1;A;xy4 z!BzIvFR(5vt4|Fl{YjRcged5OPk=uCJ+sWgYSC(g%=TWZ> z9(TMIHgbHPx+(b{a5eS|a&h%naSq#j*C{oi)G=p^`TCN;Nr$qa9rh)`CU*HDPi!(m zS=Lcu3RWKBU2AC(4r^2+pIDHh;%RrIuz6c_u_--9!o(_e*DArd`74Lx>WuQ^bCA_|0nusyL^Fp22quOS5Z zP7r>)H;7K|=TMWM32*W&(S~6)4LXgKFcT}mX3a5Vj_a{Gs)uIV51+=oCb8*vZbhv|P<#=K0;BT>+yR&4Wx(sa2Ttf1b^>Ni6vyH}uncf|cYxp7iB|wSHw_F? zFZMvaz*ME;JD3ZY!E?Y)=oSPaFXYe*MYU|m#!KA;V_9dCdUni$;kU&FE}4c$d6@h-d)?Lyy>Cq98aVV99C zPQ!OGHwr@Mkvh)B>ah0cIkLn}*b+4%ZWvXZ$3iFyT|rB5DPDp~(Oa|*x8ZfD4GG~W zdKT)P?5ZBzz0cM+_Jhnc_NZit1o_*e2YMH=%wsA4VY$ zF&S9cGiU*fM-~8|Iu4xPKD-*3Q8Es|XD~l-vX_AuEW(R`U40D<-(hSAJSjg8$Ct4< zFtpc!CESMffNT8-d|wB42G&#@$K&f*4#r9MfHSPYtAKg^4(#7a>;)XE98SmgFb}Z4 zL%=-dVGZDKCxAmdfUSUu<-x&t2nz!TJOVsq8P)+d_Z={bNAP;!WrcAx9>G$;2;T-) zatAg9Zucwji{02Abpy|tjBjH_;D;XpN4W=^0n^I?ws8Ra0%xm;3H%8BcPV%<+{VDn zfjRhNJ$R%Nas*#K3f@dX`rv1k;As+Q4N3t2x&gBaF5q#U;B&ml2>iPmJX{*qiKT#F zkHRd)M)33=@O1&0t%v{*`U}in*n>~CfLCcFZ}7)c;E@;@b${>zHZb!v@QViU3}xg5 zK6MPd3g+6t-nWCrO9G>w2zGuGn0Z&Q{NrHzRI~#8Y$te{4Djr!;9qxOwCVvK*9$%; zh)lp6YQY~AfPJTf7d!wK-v|7n4?Kf}bitx4z^28J1=#0auuv5kEoXvVK7pAR0~7={ za~}3%S%MWcfgPzMH?Y7iut7ew66}2!SiCH<1?xQo_PY>yg5{q8+ZRHnV3l=Xm-Ep& zu(39d4{1b|hXfmH~r!A|ypr7VCI0a;)l<1pW22=%`MEI@P(jXjc<}$2UumdYP40f~#Ru2?`^}L4F4Q5~+d%!*vVWj~9R`Cc{ zEck+*4E$uyrJ;tcp^o86T~J?+P-7xcOXg5dF;KtqP{a06#{y8V#!#~nP}AB_*WOUu zz@R}b*+4x}p>9?{?Sw*YX+eE?K#g&MewTxW13}|zpmSHyx+G|NE$BKC^ehXSwgp}D zfqqwlhQp8;Xv+fh6$g5r51L*Fx)uWcnu3O-K;uh5=bJ$5WRO!2Bn<$`7l7=}AiX$9 zyc%SVM?4^>AxIhwl52qM?jSwPZG+x?f3A!W__=~{Daa-Q(rJQxydaYjNM(dDV3h&1 z%K*J7;MW2PsDN4-aIXN&LV#KwaB~CJ`GD2{(9Z+>OF#lLlqUxz>Hz|Az_18V@I%Q9 zpzKv>3_NMgnqTW(IS{x&<76n60%u6@p8{q7bMQ-~h>S)4T7NqQ5%R+K{$4{1=*fVd z@*nwr1*Oz~n#$iScqll5t2xE9KtQiIjRfZUYLw`fRLqA79Mz5vk z)8pwrbSwHYx*VNCpUk+K(U;MfQJfK<;h90p(8v(T_>g`({Zx8=dUkq9x?TE`bkX#W zX*bil)2h=_(>&8wrpcy#OTClYle!}{G1WPBS*lR#>y!&A`%{=H-YJGDVkwi!L&*)v z>B%n1i<7yNA0~Arl_muynIwrPy-GZtSd|!_Xr3sU_$r}4p&}tL!6<=0;bHvI_{?~h zc(wR1aYJ!C;)3H0utqfg*;&OTssVONT!Q+Zz@XwlM5%XnSa4s8Q(mkp2*6 zh(!n`?;J_C8mX%xn4CoAq4OkrTYIEae|IPB7 zZ~IsH+xv6-pY}`h)AO73h3Dh?&hx#pDR-0Urq4btJ^?Y3?1&`sBs);+##!?JfviH~$JN)X!!(1M zoZ4~Kb*d8!mliRhE&$F#?H#$v~)V-1g1KDzcW{2}?_?gz^s4BrpB z&$+krp6 z>NSaLNB?m6) z%8Pd{q+F1`&^_cn^!5CX^M>a~&!wD`Id|f$*V&mfwP(!EJRZy%R2v*(hq49OZKs`1 ze;TMBST*pdKeJ!G|8ie+pLk!-DW6lMQwL5uocwU2`h@9;r@ckJ%X&w9h#vKx;qJt4 zh3<1*kzJBq{l|lj3m@<8+}tV9dA!57gRi5r-M5|Ee*Bo_BfXc&Bh1&EB0IMpV`;GFJ#~ReK+*7O+Bgp z#p!!3wOQT*}OAk zr`FDw)y>sm)r+bpcO2OfyF+is=c=Bn^eVF|a@ElGqV0~`CAQzK+*27?xv28}ww`Uo zHp^{7+iq3VRRmS&RQy@aE-xx~Emtgmwe|Q`=2rWyQd`H%j+W8OY|Es|o|U$jvP##N z&M%!T=_@HI@hMqcGFv=S+)x}>yrx*H_+`3kwVV3JnSc3ZE48 z7HlmDDKIaPE||){n7=naBi}WDX+B^6v%J%JHF?Q-&Urd{0(mcUhjRDlX6E|mn&&F! z&gMMK>CdUlA#(h3EOHj)aOJ$nzMS2bU7nqo?U8Mot&+`?J(+bqt2b*;R&G{gmTQ(t zmRgoj)|bq&%!`>FnYEeunemyMGHo*rGF38#GiO*YS+`l|SRJgrta28M70dExIk7BQ zdMq`T6pPCG&V0*!!o116$n0abGY>F#Gb@<+OoExnjAU+MdNW;^_RO_RQ>GD9m#NLv zV5%?`m@-UBrYKX0$#K*UqV5Tltl=>9+6v33iI58lMrb z7|)LLk3(^Fv8!Tl#l*x=V;Z6jqlcsXqdrFFL`p{PkI;=62)7Hr8Ri={5gHZxDI_Ii zCYTY-2_k}K12Y1rwt{+^ST#h&kI)`pJ=cMSA>UeFv)_Uf;+YZ_eO#2&l8g{9+ zmuzHh!mN9(c&uD3>({qi?+5 zbf>-l%>8=w%iYghpLITYe9ZoEqf+ zKxZJif1r=IZ^NnGCnrwmogjLLd*ph;x=(cRb$K6e>%^U|9nI~WW3I+w#%osX+GS3lbky5ntCLe=-}+1mxTS68Z59@}QN zZKT4t;(d8`xlDQ6*0oz7lqHpkmbH}Hlunf7m1vY)ERHM|E$%MbRK#6$w9vDVr?9gi zpg_FfY<_b7qWrPE9eL~Xc=HBx8M(%}-*Qgmr01CCkaC8yOS9dw6|-Mub!BB`ZOBr| z`jmM-vnDep(<)Ob^Be0X>lmwy70p`DTE>!OePfO>FEEcWYnXY=1ZDu!nYo5(2>z_h zlm<`c2QMc5^xqlcBk_#5N^}uBh&aNEkRl#48W~#{^BI58nRG4sUoyfn$Qf1X3(^m# zElF!hRZZQILP?289!Xl9l$&@bK{FvX{&?J{*d?(6F_qB+QO_fJB2^=d!yUtXLqkKN zf}?|AyV#bE0alxJ{bl^VZ@TN#>0RjMGGhO3FopBs)kZE=)X&vpp67q#oO zaj~AVEL^L!ro&Q1wcSI2f7wK+1| z+SL+wSohGEgMA0`n>IEs+E3c|prNn6eouZ~LT%t~&l=}ljys*JJ$3|EC2lXM+_#Ng z@wA-3+-PfPS$*lf68RGU;+CTCg^q=X3aAB<`M2{d^G@XI<+kS-W%-i!-$1-eg0e){gT zn$(;Wk7VhjGYOvY_hW5i_D8*rPz*N@T_0>0Xb>Rme|uAzx1r}1*akncVWr~^hv&AM z);?=$L8eKl{lxShyXfqJSn_dC*d&Z?Ow ze-?h$|M2+j*4L|Fe0$pUIQgO3J%Q23H~Ri)xKesK`$G1)(!qTLXHLEA)$ES!95|+U zq@;!KP}Kq5#s_S^Qq;wG0zmR{fQTcV9A0i5+h}?klFW{BQ z^K0xGl0gyK4{;2lJRSCALd=I@=x7*4yj{oMyIc zwrsg*gTPU~WBk$`OA8J146>K!8s!*f8)lotS^C*-wA<)z>tW%wddsQ^-4x9Q%zJ!R4EfJ7poB8E6~W-&eO-;&wGq2)ou`P7G$w` zZGf$Zm6wgzIuAETZwnvupjE-fA;yXN>Dq-0auog59TuB-`WS~U4A+WUoS+`79;2Qi zn=O|wUMx`~v`3^)?2zCwzLUJCxsOoy@JY6>in4OEb9Hg{ve;#o^0|BK?2Tz;e@67rL0CiIWR2~5myO=O0YRY= z(XcusZEg`rPF_J#X<7NU?K^hX)YjGS-Pd^F;Gx5o;!R9=&t#{)0zjkH?=rpLp@=^_#cv-hcS``OBZv-)4UNZOM-OBK=h~ zOWSo$uI`>bzMJP3owaY@>=NbUIbqgTf1xybg zjg38iGXC@#;Cczb-b}uIHwD-}eg5(l(0!lzG0XXT4Jc?WGcvWXv~_TFcH8LXKp!s_R!(qcz*)^iFgij-yGyQ%yXat z_1|F6;RfKpk91>iCx9|uiX_dLNoVh;^o+ZuBl75iLKW4}? z6v}t5Z{NA6xw&}1{(a9pr1_nigW*d!bLnSEkl}ZNUnSzXRC8B3@JAwX$g{JvpSna@6*)pyc}*0_YB`RzFBzv&i7T|2hS|ewBSF08@Jm9} z3`dmo>cg|3tDG;S;;BZTqnrYA;yZ5VTFzg{neT$EwsVHaMN=B9c5;|x{|{|T8aZ6# zkx!dcdN~24hOgE0u5p@i!?#ZUxqWUsA=*Hk4^aT(PZKqVeS1Doehln;g1tlSuy06} z_;o%4%+UfGO)+lRzeD=9pKdHhTbK+MJ3Dzg+foYltIRy9F@b$A-#)*(Y^A$UeSxx~ zg1nrpjP&0&-ov(g0e(IzFAp~tWiI3I&=CM_={AZ;3dDSf2O%DXcpBmuMBYm1qapqY z5pAc4h(P2OQ9@Qmi{?uTaHFBdtr?MiE>C3bGqbX@va_>` zvWpZ%vWP;0HxSI2voF)!$M$nz;Ra;BeLBy0Gr>qqpy)X)uYNbCowq&1B8_u08qf%T zE)GY<;mF!?;eDEj2^wlYVS$s`(L0);$0HNzG`(Gbk>W#hB+v|kWf_{-RQOBMb(_hQ-?GNknsd1sV`u@9@lR-Qes@>t08%h;FxiUadSkKI^YXp>r@h* zK*1w4baoJa?yLp#rY&8wIfb!q!=}__(X&1WpZ{)3+P3Z6c5F$r-z}HR)8t=#xpU9* zl+>eXpKRN_HT81l>NT$L1QrA(;bz16{O%Z$BRT=+|0JAiSnDCjLHQJ9hDXfw&vt)* z`&A>`HDcoO?Z>a@)$#oj=B(fU!`(N{42RG$OE&-hYHqD#z{t7l_nx_3RL8UnpR#J_ zsoO=3Y=?ljxf>2&dS1g9$)+W3K6>f#dpk+!Q#v#`#|J$}(= zJ2I}7)CnBNEL*qhWNu%eEcA@uI5B%`bMsf-M=>Ue}4kXZ>#9$;%Im8$>Qc zXY4w5@qR&*XGq+Pl_{rg<~2`+_Z(J~R3#OqnW^?r8bcSLb7=r->#2j~8|odJ6qZ3- zD8Z|tw67VjP$*mNGO1^%@1Wf&+GTic?qGq^3V8K6Q$?Q)uMdue`FTezVT@#8US3*z zegjJa{NOl=ok@*BV^G-3+S`%3igA?zXqi+4ZKu^!DzrzLXPFn#Z=kODe<-%L0h6n{gZBwZ&$QV@799fMdpo1Eqb1&O)vEfw4@cE@HlB*3eaSGxanj)0UkHOfRN4RgOl{ zVMK7$%d}3~4c1xaX-X10m0oMj$|;Dml%5Oyj-lU1S3$f=>V1glbJkc^8|5an{0gFc zZq3JD#!O}?%@NM&7`hZ%v#7rv828=2dGN6q`zkaq8HJ1 z=o>goZRl*qML4bt{SC~>Tv{gdR{HZFc6_#Y=CsKZW22)Y!-j+e`uX~JN!=xI_eKdg z#G=)7w$+svJic-LkKgXwzCL;0)X_0R{XLxFp~0Y&5Do%qS%OsRE_H`AeWY}#`^Mx^ ziHSFo6BFIzXC}^&Zanne!OOcJ+%4O`+i>aL!IjBLiHSc~+`D&KQ}*D&WzB;Jl?PU2 z+`YGd*}sEAz|t zU%IcmcW~pq%6kWrlJ+DeyC)_lC0;71uDJB$$$cwFo!4F2e{g?BMdd-uKz}!jfQNw$ zm@7O61!HkE(JJV2Mx&Tu?z}UNY85(e&*fr*UU6lK3lX#F%v|J2!C8NPntarPQRf2o zVylod-C=aK1=0^=-4lL*bxGP-|ENqT~#gFfP1at6y&q;{QZH* zas4A?Sg(X!44Go@HEiU}q>a0N|HIEui))ok2j7U1)0h5Ee)#(<4+^R}*>H1=oiu+{ z+P?38yjN7GLWR;$FnQ71v_s!#J}Rp2;tD*&q9@H+y>-vA^LL9BDwORSHe%}H-|aYj zI`dIsRVP*G85Tcz>AJK78JBKlzo}rb-6O!HS)Zls`ooX+3MxA}d{=4Y^pho zeqmJ?-PwQmxH+G0-h1rA?dNand&nHOpqTOVS8v^a>Zf}z-`COkE&)-{V9Va`e!8Du z(azwDgQ7;yPTIWt4;QjtmbG#1J%S=9&R?~455!wo)5YQjhJ*2QR&UsS{K~^u)hZfC z>=QY9_KMW~C$Bszs_EkJr6ExhW__Bn``C~7@+&$ST=B5cQx~pG+xPAHti0+jwsWv- z@{$cZ4rg4tol{)fO=YP{wC;vYV0`ik|tzJ>8ub#d)H{Dx0juy*^w zjLQ#SDO6Opd+3Pi%Qo!#2F}MDg_6nfO&I&hqR-R!A3JyFRb3C)!E-1WKR-Ej_t$5y zKPheDONPWxPule5@Beu1LGHVTUY=xV;_MZh(hhuk?k0whBMy$8Fn3idG`IoBQ?Z2} zp|N8>S+X{D$D!*lD!Rt9*3kb^`8_Oa=q~iH8BF*-vkI0RYk_+Bcna=HF0fogr?9WF zFVNwiMi?n{71V^neIM%=1NVz6bPfF>b2}r4E@2eF9v{aZ^Oy1zeawH%PoZm>QShu` zGO(RyHuMK~8n}Nxh5OY6ZaC*F^eK7@dWGY{-M!$~aiD)GtAIX;FN&^1RS<6rw5eoN zGA_`&8Q1Bn1;_ZEG?e)Qdf3jeV}vj-(6QZIj<&(mWF1=0A10viCU8&DrqWwr97`B- z6za#m<%6Fr!mp z?@6$H4YR1i)(W(<=lZdsZzy4GjoQ|NTI+l!!Eyl>6^!j`*ca`U;VyuE2k%sP#fEeWTh4|n5&Hj{0q+WkZZm5gd=~a4 zd=4f+gVDOeyt{X@?vsw@@^agiNisrteLd>-oX{ii%Sn3%sjDmh151qi0$}F+`Bb3b;Zb~i7Pgz zq$H1Cx@X__ce73$+*5o>KmO5?EvsFJxWnzu;Tkq}vbkEYgE3=aBT-lQ}Dsfao zg8Qzxi^+*nJPz3dYj^jA-KDzI2UoA2m7G+${fqr6D|WBnyZ_TGt3ut+zdv;3-tjFf zvfT&$7q1!jV2|O<{^YeMQ)VqsU5?-psWc(cWAXXqBq@S-`|-fFqT}}qAVe1%%+)hQ}!J{eD-h#f+QgX#0N4~NC*oS6ro!` z@kK)@u%3q-e4qWwOa#eJk3))1CWj%A-d#zb=?`l~_Sy8sajr;`4~Ig4w$KDAia|mU zR|IK2jUvs^W`6$TvaH&Z^{1LQcYdKMG!G^0q3`1-IV6k6xh8m@4>$Dbw3_yk{Jh*> zu1$-Mj2ISVhrNaH@$Cvkb&kl>0IxohfwW|pQ#}MShvy0o;PD7A>qo%Di>)5W%YnRR(6Enoe)q&4u(tmxc zqonv%!ON$2E*)MuZm6e|fQ6EYcmz^y-kl%6JFxBZrL!lGl0}9FczZ~kL_!{i#XzZK z+nXd0Z)6-uT{6Po5k-&-sZ(NuJ>UQ|BC-x3R@xrs$YcNJjg=Rl2HO2r^X`X@)1&=e zMbMB2bp$-3e6TUvne*2+#-@jRKM8Z;GokB2jiKY+y;JEcrYD5^xj72COcWU~bi6vB zGBL=BgHi@|>jk&!4j(Ic3k;tZW7Bt59TR>`7U(GI`bKDZ8N0T?n#k+@Z-+ z4lG)^XVJ2G+ZRmOx?wAVP*Da4LGUCROW@=YFf4xJ+?A<&5xCxw_kKu6x)9Oa9YaU- z@6-J#h`#Rf6bBMw>U@zlj7LC>-EYrK^I($@V@tuM^x5GKWW?NEcJB|LjrQRYk$!dE z%ZurAqa;iMGN5ZKz4QAuV*~6_m|>%;_658$+>JxV_6$u+$)CPiJ3h#PLBb|P-(CIu zeER$t4<40ZouJ;P;@jV>oe<*0!fwPJ$m>v~bB6%Y-W!7=hIc#s$cVB2r&&%!#MG9v zQzjrH#?IGgmj!d-o~|m-+BMaej)Qa9mUm`#tN@#GL))v%>7Rt!Q*aPUclrH4d^XCP zhaoYm>vJKlNEap%YiV2FV19!g=tL{7uF9Nq=?i3@d@HU2V^4k2&7+@B4s&6X@ffax zVMzN9dqjJ8EQ%OE?C>Qa=GM$lLwcAp*W;pTmNYHXeSDkbS(vE zK8>`;-0M5u-THE7FdxgpfVw*8%%)ME4C@}MZ!de08WM@Tv3!A)4* zkOxsmh?%6p-C5WE4$HN_9ZH0Xok;F*q-CcgoW}_a#PEKnKN-U{3&Yh@uq%>vK78bq*^82qL2@0C=p^luGD(i)l4PG`sbshWm6W-h zby@1-?ouWGTAU#6c0T4j+_}tYy%Xwm%F)m9w!?6ThoTr!mVJ=@Sv!thny^(cNpOSD z;jiW8a$UF^;b% zmbC*H`)ka0=1Hb~#vH?dez-oRFH5J>MryZdvei`ewBA!a?W*Cbuax!Ok=@^PsXC{0 z{@fwz*x9aXTijOCIZNf zM^>z{@^AkpxQf8}3-1_Y!7UY>T;R>CqLQHkdoNB zJxq)rLHQBXJ%-mFLz~CY_A%`981{X<_rOh=)2?H(#U5j2&l3*CLVg70$54k|!`Lcg zI_w%|17&L;cn$My^@;g{KCENIajkwZzZecETXDi`R%{q1*vE=td+d+0l7lG5m~3TC z#&p=Ve|H^@Y4r_#VB=YRVtAlGt1rkH9&79v77Q=6wPL`qVsT(`!C0&@Lbk?*#fim@ zF(yNuHAj%GIl=nCYu2%#536qs2lQplJsjKW6S5T}h6}@i`GvMtY#8R|xkDpUCxu15 zEzgVk=4jaP!o^<=Ut-D|ej<$)U639Y{mye)bZXF7(U%VV6g~28Ui99Jozbm9w3utj z;+Q^sSj_J&V`C=IUK+EIyDcW@=)ssrFHgkGzj`S~9dkEk$Clif?nUJ>QL6TsWq$oJ z;S_2tr;r<4)aVquWQtd80c%JsB8iC|NFN>hV(9c(5Vj2x^<)M zYQz`T^?#*pr_4|WKQ2|YPd4S{L0QC$!?M1-qq18ie~@`8j?37+CuN^ePs^M={wTA= zpO+OU{V2P6@UqM~D^oV3@rLZJ@V4y!xI41eo%dyiM~`GobGEEL=DF;X^p~>HFY;yI zvR=tdv){lks+P)n)E{KdiIuYQZ);@KwmR95u}!k+zi*W>+B;;|SbeqTrJ(ItW<81l#Cr!2c5m^e*55Dp>$V zWC{WNiZRI2i$K*WNAM0fgClifVAvr6L^n6^)nj*XZmtyAYdyjHL*AfQ>I;1C`+@H! z1^`@bAXvXP804EmfMHK4=wc5AKOPGQM5hSQbSe_eb{-C5Peg-V{8-?3PzK-*288S5 zK}1~wNS&Ano@I>$9nPb{fP4(-tQ`x!i5U;-zMTNtJ0^lHvdQ4cp(((>d@2yTO$Qs6 z&j8GeGeJlFC&2798w5|C12*iO3-Yed1FZ7-V8p-zFk7++jE`9i%rlmNRi7>eUv60j zV!liQXTMqw(vBoU{42oyy(@uk+o#~vnpNPyoYmk>+-G32#~MJytpz>hYk@lRbKt!F zcVO)3bzmD~J-A)C9;o(i036vyz*lYr#*>@Ct@soG8dAU^c`C@X+YHh!Z3ejTEnw)w zEkGpu0(^h}3y?EpD@Z-J6+B>X17}jU0esmupn+fUU4CFYNUYorZh57FBcG*#j;m?l zTuU0LaFzr41UcA|A_w>kIVip-2hMNh;Fo4ODA343aK9YpFC7qV9}!_d=0Fxe7D0A~ z>ekla=wylf1y8(^c zxcHA?pY|}|XJ`TX!6OD4B*lXDp*H#J7`snePG2XKVC}P5T~s(Bwy3Z$7PG6}Rtam& z|JO1Eg8q}f(YiK29zdTA4Fy=g9hnILgR}AXE3rDR?u*^F-zz^1Y<_I*)7I-%%Whij zJ?_F9_7A{i*?zD5o>f0`+Y?*AY^z>Z^bD&Phb(#yD%p7-{X_eYa&wlPL@E88dzL%ehDpbYD{zt*Q+7?fch zhx~>t^53?u`1!lU4}DS)AE=i4yCB)MO$ekxE!3A-wQ(P{KRt^dia>J6f?5R1Hrpo! z*a*zZzqWl>XSINf{HJFKqL%)ueNuqL{Z>26ww|q8IQp;SVi@4K5ZSL7V1Gz0V{I7z zAz9@AT+c%w+u9s>vmPTw|2cvT+Q8Kl_{3#! zNjAs6@f_5XnN8utqJx}%^_9>bT!H!e#UJxEEE@CGSdPhqnB5|em=Q>il!yXB78bH! zAjr1rS-+oTp3!dGINqXvTM$S?yoY$7zB$BuO~jfA zucMfZK#FH#seHu3fIaBcdU09TmYy*SHH!kyj0POY6P*31IdzO$ss!+kc`a;f{V3D zkjM_OWu;A>2l=z#w+%;-+3y!L9^{{c>-mx|g4q9Z$#;|WzThaV#no06f7?bNVLdl> z&VG*|ZNstN2jMD*KNIub{uc!KIF8LDL;x{CY#2iw!~!w>h2(E{1l**j!a2H0=RDmJ zppqfTWDSgpGg%{lJ7|NJqvfyjt*a{>L3Ca=3DWC)*s@ZAFuXm_dj#Bl^Sp!V!rM#W zo)%FC_oJ5)Wd%Y6QfSbtH?Q7oHGfI?lCaf`wL*hJgFd!jy+I&hJqv_+-f;hk#CnIf zBS?u$p7$fT+t|i|Xb@!3w+#(ssDp?gMjNSQSX_f~+@xbs!n{76tQm}RM*#94(0_Wr z+XP^}r7g9#`&KextkWs`EHmwdXq7(EA5vw^L8c z8lT*dW$w$7dFH*9iN0u*iN4jya#1{R-bMpszvqDbHTEF8OAOA4rC`Q@F9-u5McD;}ePJ$pPTdpHSX22TU4R?P&jKA#OvCd>nen-+la^A>}(7ng#h zyd;qEA{l&sb|vVWy$YoFt_HPh*8qC)T99x5JD`Bi)9aS32NPFp0LSKR1dQREfQ6O< z4&{pc-VeEt?79q|QxUGxQrcH9bbw`>KjC9w9`1|mM+26}IA z0}Hj=fFfi&=v=WK+&Q@&+|Jt$$lC3ID^3HVgfuWIDGj{cl?M9Hrh%>pY2aCD8o1Sw z29$^#>=nqtAul-?5g`YcN6A6M3^`ygh0opB%0bc=Ie5HF4&aLhAUY-ok*DP#=YkxZ zyDA5qTXLYiD+j5Mbaf50{Wgq8mT zBS`vx!5=Bz_PXV~O&5jTPw`Oy@xO{d^w~sC*&`yy!FmJ?Qdu$lyx~*G`S3F?w%2c^ zkD&Yp>X2Xm?=jXUc+U0VH6#m_Mx&~E${G__iIa1d|Y_~Vw z@_6Q2*~-*f%KEtmCOx_fC3hoCg0YQHS28U(d zK36)0(XG2&G0d}t_m0xkl+UEujUsy(?0ZU$l*d+WY+C@g(1{JwaX!P3&?&^+MQ-qb?uqX-@A(Y{W)6H4l4nej@Kp-;^g<8&&Wht$ws z%5||5TI{s0dIL#Ea_JOz)-cRQvKlo#w1{Z@)@%visd@ZcU+?!+vVA?L#l@Xk(a+=5 z*_r!r0-Bcsd5aj;^cF?Cq*bdmn*}v?0$Pic$+-$LtwcMNPLV3q zg-VfgWfdH{!Xt!-w*;czq6#KeMRlN48nhHaeZ^Z=cVl0CtX)BcN*W|6cYS6wR@HVl zMlKJeH?}oA6THEPI4N;HI6@KI!`aRw{8%!f{HC^Jp!Dwi_?M9t@?313Pd5E2UEcNm*U(S#`jqtaO-kby z=wsTjV{&(2c7coqL51 z6kfMdsO%H8^w)&Y)pebA76V1xRHszC1?cH+qDgGN%Rnn>2uUjL)fU$Z-&bfNDu?ND zQZ5oEiKb}6iLSjNB%Ml+Q{}cAc?0(3Afry;QQGrb${`tUK4OgOznOofHMrePIMPD5 zW2sc_javE#Npo$N*~#@4NmtRX_o%~t=+Oo^D?hYx@omj&wUW%LYoT>{>xmM}TW#a{ zk{)47dted0v$KcUai&4h_I@GGUJv?9_|2|mS%}xaNH&DyR;FM@;TaCL9d-FL1|>U<03jP>UmDg z1|hq)s835&b=#ZGAvlV-SEJ&3P!YobjmkBKD>`10mOVEWpmhurWr~znM_Vd=T1`|p zwmPeM97}f%DxeU>bO(c!6)3`~T*w|qZ7b8_-9V>`KD*+b=`Ei&P)#F`Q{$%bQqd{=PU}$7Ns4$(XX5X|IcQ*+iS5n){ zLx^fzAHBhj{MxlQxZ5012;T>??1Ox^q9MLLFNHZ1AE=QmoS{Nb2F^ss!fAjRSQ}9Iq@(0@ zoYGa4SgtZPJCmL@;ze{#Ev>S@(XLX%N4f`CI3l%gz+XA=xGu8nr>X(-`?nU!yB;T? zb=B26brIRkHDYu56IN%3vWgiUTv5xc)K?mex9c<|6j4WgFO98H2RF4?$`L^ynL;E` zyhH5_tWMmhM)3z!WojI#bnWKKw4JY{!W>QR&`>TRB;Z2}fzyw;8QD(mEp{}nR>~P* z2nz!TbV0)I5shjWPd`o{eLN+*Oecn_s~82Ev9ACfUfN)R`p4*4WUZ;#eWmkZA3j;3-WiIMK5692Jb+JFb1 zL2XB;yur8Jxyh+lJPr}Q)xKdhDGlt>-qL1;V;k4d=xB5%H{+STZN2;;4!*X-S@}Mo z5?Ag#qlAqzOUE=jx;APu@o0Uit}#3?9%+e^){?~m1$6#ElZWdNqP>??goc$94UV4G z^f%qkoN7OA#|LMYhW?iFu7_vxDtlGmK|9T4*pJUO^qVa;jMsF>?nb2>v)4y-w-V(V z?Km8xroI>TX=AYadziWAdR)KKDby5K)kP88InY!u9+W-1*Xy^yk#2mU9aYGu)z{K1 z-*mK>p~1v9ZisI&3uU{v4ZN{esCCWFW{y`cqA?f*0TxA*ifHU+k%$e>6a!n^`L>EP z!~K_fyEJOzWTo(-Cy5P)$S=ta4--DMnoQK!ZK4-e@*PjzVfXm3^&2rsKgSMFK&=b&FxVspAQw z(C(FH$gm05(ZCPC@VXpWbpTpZeB^|uqCAd3sf@}dvG|hi(h?Q1g}bxWn@Ejlsqt13Xrsr}<&n`A*DD=7 zJ)6;Fz;z6mLR36ldozbs=Va{ZAolXA1S7s@__how^_aRg*!^)Y>$$u54(jVMhf-}v zaq2WiIwp|a^1^W)EN)^%G{Wm6eIT0-Ys7wS=+q`bL4A(TA_p^pr|)UFhJV@rtf65D zK9BU^``1O}7RH=_T9Pl$zOu5hm_Ync|FXK=qRusi4)Hac-P$c~?mVCO44iR*$Mp`N z$3K6I&J)sdwA7KFqI#iY6RuH|peNsR7X=LexhsnM9LMOll-bcu4h-Cw$?)jrF@@Sr z(!?J`?5HAwG~7aDxzySDxN2*vei`l{%y07v;vtM-XTSf2lv)uQ!BCAr+&#QKEF(ou z_0{J4_)>$B-xm|mq4V@t^}F;uk>v4CPl$66bsHY)yqum(-8e4p<&_dfcs{H7b-LQr zuDueWFVfcP>TZ9q4=Bsuk-=~4VLJ_fPG!~NLi)5{62k3?jdu8kM^XkQqGPte(xD{y zy6SpOFGoZP?FX9fv~Cvis{IUvw=ENDLh1Pz2uC_i!R$9&r~YOGN*PxcXE3$CZtd4O zDfRuVCO4+Hv!O!F3E)Tc)6_5h{UyjbB|n#_Y4NID_Da?h>gtZrnMqVtaC}rI4ocPx8iU03wkC*M$ zA$J3d{`9)SlEbsOl=kW#`RHnbvK3;r8$n@mZfaQ|N-T@A@9%iQEmyYxNavL}iGt*@ zvn2AW;I?3S>)J0|l90t3a%g~hEHOgcGsMp*s2UDL0^x0SM-aYHlSJl+^()-JahriUm?qKEO{GU4d@N~_+J=N7( z*V0FLI|`w%zNpce+|F@tDa_X!NmPMKS?WZPn2Ig^8|kC#-mD32*SvI1pthXL*YR)H zED5RVt}k!aII|dSf zn}7liD2j+ODk>@{D(=7?0TmSi6?a=1U<7nngh7EC!KI0HNi`aySzHpgBqq^n6Se3Y z_gxWDQCx7xov3j)^nc$w1H3V`Y5RR`zps6h^M2>t_1tssdvE4C6D~P9AGUFQVavML zZM@}{_03%#JC3$Hx!wDT_s$ZbMav`B50BMxb-MK0?M#yfwjK^GTc5k%d++g|ErztN zcl-369TzXD#}Cf+3OQx5`U2*sa~``>rANr*s>i-Bo)#_cX!)b@$yW9GQ?(B}KE83m z*mL(MBfr{q?pdC??(44Q=WbqT?`M2kuj%9F&pQR&dHK^-n@;NPLZe!tb*}k7dtz$h*^b&tFd_p-$H@m~tBHPYO5wrIQ4BFeqg zwQk*7wVu|^wQ1FO#DQCN!tTDR^LS^3*PAwX?JhU$@6qGdE9*Na>slY!+RVbmvdgy5 z?!H;5@Aqg(qrd_i`(yWRy>Yti^yX3nhx_NtEnQXaR|fiAQMm^@Kf80MK~aOomOUTU z{^3lwTYJJPn(n{F+zX1`uLjsXtaxy*-M!b>bC)#ftGUto@~id5N8NoMHncp^;Mw!x z9Z&DIsO{@@Xzp@Sk|{MC~jv}Tz>xLo$KZM?$ml!=gH3E#=DE|w|dk1xp$ePYp1<;x?Fo{ z(O{q8d@kcmeU*?DV6nn2z{N4BQEv0dZj*DzdA=Uu>R|cErJVsGjGP8VHYRo?a9r1n3tRQEU%ew zuFcTsysz_4`5nn?pZoBg%(HXXOwX@aw^2R8mT%X!YbS0fAZDdeDFI!0-{TL?lvI*c-(c29=JLQozSBm!kvnp8^*vbpd?OQ{trlWi?0 zSXZ}gWZSCJt|i!*>{_s`ZEOWgAB#1@2*FoqDAbXDefahf*&)1DJ9U2Jac(+1}oMt=&Mor?y|(YHgd^meyKZi^gLnh)5((<0^1) z%X^uPDhuMe%1R{#<*c>J4)g(SL4UF}pgkB4)&@rs<3R_|K>2wf?|L@bi-{|#z4cUY z3s{FQNXkD9^8Sy4JZ42y{sPGTE(Lj9uM^8C{T|un#3#h(`=19h~dO2%8w?FB#tG<5aWr7L_PVHMl?`* z7I7*uuUL-jJmON&md``69G4AXeQ+d&pI!+_vv|g{j5GO`@Io#;_HOk zxo}?Y|25c>`&VME^5X56$hHA&$H!SBm(MSe{VD~U^Ko6UR!R3Wur2ooY|Q%y9r(Hh zow*-iooefHJ*DSU`Qi(5yzX6){c*Txt!h-Qyq#%1nay{YVm(#G-y8K^`Gq+yR-2)V zhl^Z~i`T{J!8C0~oK`QVWfm}Wgn3TZ{u8-Gd7)<(PU7R5`omn;tKx^AMyY$ogbHUx)zGGI`KjBTWv! z92OK*<|02{H(r~mH>l%MQ%o7^IDKkHX1eSPpHpqk^{IVD^&|u0O9iU>S7w{nmt6nl zR!}A>-H?gV$0uc^>G6M0hBYMN zs?X7-tH+~AYoRJnYtUsS8LIn5B~a#9I27}1ov9X!Uo%kU^=e2=*JTvjPnlo)mYD#u;YG#HSG1q0JVP*03a6Bhw zL-soAeQE+nb-SZqH9KQcxiww5&$DP5H57eWbnCRW%g zTjJxVDB{&#h)0b0b2lV4y$`OLsPxo0T}DP#`M6Xv=txVQLRu-4{7p)cEE_>E)}fpx z&`s_wsix0|Zb$n2)$~7B(-&0J7gp0hsHQKfrf;#V(*ImdcYs(y?8zP{TB)RdiN8B* zrCJLaE6U8Heq2v|rkPH>=lFjb2WOneUt)v~SoxaosR}oMuCF-d)On2jC&E39)kB zM|kkP)lQBmn9c0C%k6Qmbpz^@pS`DmrYYHJj!__+VyTP>T^c3>i09# zJq!~l-5<1cQ_$k(VSZ2J{WgGDl2{R~A#M;Gh$EyHUAwk)E!z?8iM1)Ojwz4YbtKlM zc2$(-3~}K?>CGs;3)#KN4k0^=>I|Xup~Ml?{wV5OPwB}JHT^!w1Cma@=8><{i8CmD zCbct*>Mw+}fh;F`75TB6`dLTmKagL?DgP|xkFu6Ov$)yHv2eR#t>Vw(k>CPIF{JxV zYt<|We?A*Q;g+>30Fnhc2vL_=s}dnwA^iD$6fB0QZ~y&gc|4x520;f&LK)pZ{5&6z z6n(XNow)ppdU|MaD5XbE4v7Adl2X;quk63Zc5seGom9y?gPDi)#QS9`0 z{pS5t)lY$yiF_SwQ<-?=PWjcopf1|WFUn1(QPX=~-Wt8Xt0^8x#VZ+Y#`AZ}JmNeC zzjPH-o8%qu-u>XYKK`{_(?V54>E$w?_%{^om-&XAZIFVGQs*IE?@ z35P^Mq9G$8V<9n+L`WJW3o;9`0J0Ra8nPa;0kRRY1+o>A4>3aaLJmTXLJA;7kPDD9 zNI8{%4iWBItLz{uhzGi5=>!eExjzRnrFNpd{xITD&9l+b*`MjOX41>ViGU$?Hb$FihHdCSTc1=mV z{Yt&}AVG+N3>wrSKE6Y?)J{AOAN3#{YOZAC5W>QGCMWllKV=Q&*BkeTU)Ox>u(=~6 zaE_PkM5G`N{GP?jOLqaPCp~p}H&nmMrgkzY#nfI(^)zZby(-1jPnAvm@lsW31E8hw zvS=-q_YFIpkDou~$j;{FxQ|3V&j%BvHgzb8c=CHK7y;iW^H@rEXH)x`QmfgfexO&S zP@gEBXzEvb|3H085u|>l^3*pZL+X)yknj7n2VwFjm2C1$QG$FlOY049_z^`MgjWZ| zD<0=;>OY=dK7v{pL@%`|g_oj|VR-dK>&ZB0;KdJ}bgv!;pZ|ZT-+FnQUVrzefp{Uh zs=xV~_4doG#Pn(}i(mPwUVlclm*uZ~QC;}|zkcNLKOFIU=`TmjHT%;MpWtstDE@SW z`Cqy)|3ep5f9Im=&s-?}%Ed4Jkqhac#cSEx+1IY);OJCW=N)OV)k{-?+PpYH!(j(_jqkkCGT`-Sx%Ffe>jL}b+9Aw#2w z4IeRb)Mz>WHRu0V#DAD{>=OmrZ*!K8=}b;v!`xR|;J>zFL;bD>`d!0C{{zF*KS!5SVc|rt7h9+Mw(UoIgR3a$>m}~=;{lgy)q_H zg4uqQSRo&|g5p3w#JBd#l=YdZzKI&C#)@SV|ZeUX)wx@pmrf0ZNs>qv+Y0ezzMX@8(Fq%u8P7*W%H;*5t%+L`f#2TC?IL@*o@1~ zXfWddGpfz_{ECtVW?XN^8D<=7#;#^`G2^{bB@df%tr=&TG1iR1W>lL|P*QmWY+Aqb zkE~wAv`wuKT?!C{tOlRttYBwvHEw;btydrxWs7s;*Rfq*9v#+~dj<*`=Usjd-{CpC zedxREI|d5IxKA4P*~|)}w5P0s0|SK^n|VVXe$PTD_zmtk!VCF_gOWeo&c54g8J-;% z6eyIoO|xyelU;alhK2O<3l#E-rY=8gWY_y=&1$|S0QF-WPA%Kb&e>ha76t_(KQ(=B z+k)Q6aqb*_w zj`f;3Xk2&rt6J2g$!Yffr;eY$+}I^hC||L+Nx^A$>bEcFeXVI7C_E4Ma{K)m*67E% z&pV`h2MTr<1h;^*%s4svS&6zc{8`Or-#*L!@F*nV#di$;|6$IlrNwMSho-jUpLRq% zt-P%VoMWLA=WWct1^*MpCoO(F$2>KUT-AT*ig=WK{d(DX=KRHb<325O4iskBpZZZ~ z2`g#!XXZZv^WoNd`LR1CZ15-Vm88sRh5r9?=7$e1u-*FiDpvfgLj64poVs3QXX=KI zEb;Njd|$Ets^}tn<6iDNxVRJA%Ze>DTw?hn7T@o)?dJetV|#sF)n!)vxZ7t_j{Cs> zk3T)Q;WE=7a8fx2HNbowS~H_%DVuj?X@uUVd7yAXGuA1+lssm{Z$usx?XuJ>4q^|HFo_U}Kt!V*7U z{riy#?GVq@gv&Rtu&-uro4$Rdd!UfNvv{N5Rrb5_VJWpXW!ax}$>=-; z@$s1TqK$Z!-TUE`w)>nn0fIxM{|MV_%)dN#c-bd>{eHMUFZ>$Y;lJVaB2AM(;pmNv znh&nA%_D!fQ?dy0h<2a&aq%@4)O7v0V+SyQ!n;pSG``MewRPHdCe@aY@5Gq6>+GAu zE=8xy5Dzc^*s?FKv-nxh7JV6s@$0i(3(Bsu7G3=cjGHk2y`Qv7ZhM0r`oq)2=9cLH zxyRXs`WtL{O4pO${jM}XugyZqWt{G5PVDIb!OiQd84qr-oqf+cbhku%HT-*X z)p5P{daJ3d@w36c-ED%9f9dmJAtdcXbo zkC}T~%JP$qyI}rDJuCiZC0iv3_Ji9tMtXD`2C?5F8J#&)$s{=-pC8?Iv|(I=Su zjt0m-V7VaZEB5ZGf`cOpo8fxc_uR*@V}88n z`ROKBG;C;7RvLu%bZ;8FZe|}Q%(KqB+70>p@>(z2!XB@QJ+@(Q2l#vYw;49yvlZ{G zYH?yuL$o(w{*;M7u$+{YE@f68sDC}8&Y7)jMtH>08$u8C@6~)u=k2V^hy?$%ANlpM zF8ccq|H2MLO!oS%QybjBZdw8aZU}PR#l9_{d8E&rrdaO=SGIK*E2>!Z zW1~72up@1L9=w|wr+91ZH{g0Hed6KwY&Yv2=k9pmC(L(LcHOkadsuwBdp5i6iScY1 zYG|{U`47zBXMdc>U)qbQH)kJV=_|9Ex2WiZ z^6j@@t96u3-7)N#>k%G5ebHwNkFxX)Hy8K)-YHO6P*3~H`53FSj?iXFZg_XoW1ws^aVfNRipmm$s;{aFkwN% zJ9odcMgJw9dCN|)#3hfOy_3-#_^S;eAwWZ^XHRn+N_G$pc8>;ucvEC`AK%!$)QF2 zk*)DO366AXRmfg=uJ%?T|0)hKPFh;Xvb!zckkq3c)^DB3 zyG|D}(XQ^!OLux=J^W?eW`|R(Q}OqWmVMAY@E5= zoPv43Q8LO(N%fb-3YHF2(!1iUf-&DIxpbV81$C9o+jB<2^*KrwbW}3!-f0C@>y-4? zDXD3pWWn_!1!LAKnK)6&=RQhi{d7vfyzNQ~GnITEp=4G=CDX1IDp>j_C5xvi85W`B z)+S1>EI+B>>^(}REm3l0l9F4Qk}F-56mAzNSiD=w?#q-^Whj}}UrA#tC6@|HmTozr zU|y<{>b6Q6uOC-1W`&Z%XeAdkR?_dxF$IkuDH%0N$x?SEW3C-luza-Y#qxULI8Qbp|@{dSD%14s->_f*xQz*a*~v&Y%Hw1E+%0cW%Ij;5@K7xEO4~ z=NI$>KLuOz^#!)#*FA`@G$ji1_aP-3w6d**Vqzx{<#-w7gF5M-7KQQp)YNoNZEOa& zlT+iz3*5hW`73YZ;*i0an4OktKsgkU>ZMbDwjZP;Bt;m9FI&a(v=m*IK|3B_E*7dC z<+-NsvYCGmR23=+7N#^mS+`T!$iFoLt@u2F)_k5+a{T?kT6{i0TRsn<9gja~&(|9$ z{nkn)&qIt#o|i<>k*_C}JkMERUC9Y~erJQue0_s1JnmpU9&fNdkGD#m&y6a1zP765 z`7^5Ic|8d7byfgMzjaZ`^Ii%z0n5OqJQ|=U_#9LVIGpA6XXh->yUJOfcQ??BkK0+E zcWb1)HX0UAIrFb`}A&I4P4OTpIQ zYOoEs5o`ta z;7G6+7!L-4X&?iqf*No(*qg^43;|byq2N}q54acX3l@O=zzbl1unZgkJ^=@Uf~$=x z9CQF9KsPWF^a7*!dH{#;^#Bg%>i`_V*8w=1`v>ZH{J@EP-a$S03!KjV0xfU@*#KID zeBas@+zQ(s+zZwQ3qS|(0;mGZzz&ZdOKzGm$Yy$d$K41XY3ycPXz!)$D z)PobjS)hdj`~t1Pm7p!S0kj9Vg0;cDpaWRI`vEWTcEKmS9Z+b9c2t;8&>HjrZ9#9) z9`pxmgBs8Q3H~%jOOLQ7+wy{;^ov>SG*j!n3n@r@_cXu z&-a2KJRdyB^T8sX50>(LZ}`LW!Ph(=v}=TPANT{>gKDrg=)=?faDDQ0FqEf*Q9Rur z*C$U06L~sl;OX5FFK&bLxE+9aaT{FCZ4KhZZ7`oR6n=7s!B5U`_{oVIoJ5=~(SQ;Xsaz%~_a9I8M2drs z>e0C5{$Nd(N%nZzU!*2c|JfW!&5`SoU&+EmN*_<-(^CCZs+UCNGAMr{F`N9DLjL8D z{|1VK)DHiy52b5~I;x*S?V94EB|C-c=}qy5@ceA4WIX)ANM)aq;*0t3Ew2yg!9qWI zjX>{%9BExh>tr;qE2W1D18IG5y$`JsU(_5TuM6mXh5ocQpiAkAygX9FX^r?|hS1vK;~hxr z#}^|Hr!|ChX)Ff%H^neoOI#m9>xuU}kk%CUGnA)GZ4RRt>LhL`JzMwtvl}LAXc*A$;+Y1DLWNv#Z*>`64rU?Gz3bs3ehPL^UCA;m~bJ`JYp zO1dx8J=f%ij^aDgbX_5}4_z}*t^r)PX6r0O8l#@d z=;%73`9@z6W^+m9731%NRJz|tR=>*UPgvEx1pP(Rn7KZT#!RuNF^34fm1B6@KNSGXcs`}_p zebBs9A0c$#l>DQ0pFw??%@OrCR57MOvcI(6`&70YC8dw2G9eVVn%dRAHI8W5rgleH zi%BR-Dce%c0or=Y$4Gc!YHI-L8PYwj57o(_nX9TZ3VBs?5?mE8>K|9ESsl6(sZOvd z#skTmntBrjGm7$ePWd>4uiqw8sHUGjZ%k-``AH%qBlpb8I zd{njc!KOIVU4wLtYq&{A%?OhYt$($4hA7_GVPrH<0(~atV@jjX`hLx9RFedG?}X=0=m&&hY##H+T*bRyTc9zL&0~zDDVefp7w$gVfW$V zq`e>mY<|7xf$#D9v^O*lHlGU(?GY`7{W-WATnKIid5rVH&EP@sYuanzb5#U;F6|}R z@^Qf)!2O{;rgGR{@Nt31c)VNKs5bENfrt3KfFJPjf!n!X;66Ssa0_n-JOhpe3;4J| z>Ddk%`FOxnw0C9C#{>H$9|w4mj{`i*#{nMZ;{gB6#{ur*{)0teDYzQE2Yv%S2QP!x zUN)*lJnmpA=mGu(^ahWE{@@iJKd=N02QP7dz;j?cxSyA&J*qU=I=-%G4{9oGJ+DuD zRkL9y@_gEpTMRp#_MF;-D`98wIM80*2H17APFZeB30P_3H1@L>Y49us!qaff3 z?Af#j)s3gOv{B`9|7h>e0d@rUhxWqUU>kV5w1?*f`#ZkAz|pif=m-YDj-)*`Z@w;I zPoTXzPkvp&*3urL6CWq+DBch4E$U%^$lC)4)83+rUvIF7&>oyGPlugOdu|>1^#?nP z_Rf0p>k#$~+LLsqy)wqHOQipS#|a!tdv%@oxL{|~9$`x!H`ocZcj(3A2YWn^8~8r$ z4Ym_-w6akp^LT+XX^$?D#|!qmw1?M=#|!o>+AH+q?ZW)s@$SJ%YypT*~W#^Z59| z6+C|6dY(>uw&k!#(q3&t@HOmFv?m$B}*dK%5;BRP;wllwuVdv0Zss_}+o6Fv^u<7n@<3%@_Xo=SVxYQ8>U$I_m5Q+~gK9YcG@{+zIv^Z0|m zqdn`^JPxpv_&C8--XCbi~yb9VHSf^(0|Zr9MGOt<)z9Qz~^mTB_2sEA`}R{ieb)>65CZXDIZl zy8K-n=}6U?-oMj1&h*~QEL~sq{*OMl#-b$c1Mst?r%2;Uk@O5HU29f1j;HWCh6SQ z9Fs12S*6F4PX3Xe1e){-=!0}fRXb_iSJDl5k&a$7WS!Pfl|Dt%Gq`WEpA^Sb(z!qS zDqWFYRX)Bd9p|`edPb$5!2KaT5xtX+kz|>4q$Zhk+F>FctkTn~>DeY7GPzREtd>5R z>KeE|q-TX`wL`|&C8`rdbXq|nD&jNGwmnwGwmtRdZm3JoF!dPt#Unur<0yul}_uD zbg4|XX}?E0(>@%|sgkazIU}8)xsF#=nGDnQz*igfMSFPsEa?WRoph7V&sCq_=}IA+ zR)3XEE7!FDC!J~kPdW?mfclkm`ad*~PJWWk&$LI#&yud^I+f@5XsS_VQ!V;zZk9j6 zEI);MCmT}To+Pa^y`{Iv}BR#w7NrS^s z6-Vg0YI-7coVi|g|D(NAoVkt{%?It5X7Vz$r<%rNO|yx!atu}J$}!L$>10^6w@Llx zK$osXeq}0bgThWR>5z#gUHU%=kdFEZT&M9(k@QUJ=kFcmtYdO=!}i-UM4v5f^4B)p z#*kR*);cKPl>aKJzD2EX7KwG%CIxJLevs!I8zsk9=8tav*`hmj){3=OoNixhaUsuN zIlnNoGXKPf6W?7mb+Z`v<+p3EzEdo_e%3!`RHq{HPA2>grZ~BDQLI@{9S!QoiQtJF}^OBQu|G!R(;=tcLm`_0MYPUnKv< z8vGY&{H%uYixfXrL;OUFzgR>3MVddchWQg|{>2*RU!?WJYFIxatv^=7`V(pWvKrQ} zNb8@~u>M85epn6Hk4V=atKs?+>H1|gT)(35w~n{#i&Q_LhWn<(to+Nb_gPH=loz=D()(BhvZ_sA2tywEpsISid5zUsHYa^)J%; zH`O=4enh%{D8In``V;B;tIRjMenq-|15DSi`Fz)K{fjl!ue$&Ia{pELuV41R>i+lk z_?7q1x8tY0|0?7E*8RJN`K!AB|ML7-JwM)FKg#Eia{blx{4%ZI8lHbu>;LWNr}FxF z`}wQ9{>-1>HC(@}I`fRm-&9hv)N3d@Mecc_1211fj#wruZ~nYT=) zFp1K`$ZkgVi!#|hCDXWp?Du5mX^8=5zcYPuOZKyX_ziK6Ok)DE52bs_6s(9>Z_4fN zlBrom_H>y-tW0At*gY;ZlV0WsqrxJJDHjf zWeUHe^cb@H$;|UL`<>~lYjVA-*T^rjH(jH7BYQgKCz<`uw3pfMOdYA*)2nj5QnTNg zZlUz$GL5sz&LIAl*q`W6c~!AG&~tJs;YMQ6u;FbKBiN{hd&Woacn48L85 z@_A$9Hb-n=_Gb?7_+a_~*q!s{-r2}*H14qYqlOVE|7C3Xmz!DWXxH`+o&8`xk4)5k z&%R?{&VMwE+rR0Y-)I}l{n_gNj2N##L1R3-ZU0}`$X2@GvLDcY-i0ga={woj&pWsH zvOU^2I?Xsc&&X<7ZgJih(gk+so`1Zsi-jAKzn(V= zK6x)o`{O5GEB3(um<91+#(gZY>$qt}`@CUiJzQ;jfIYw2WYnE^BhlZUm!rZDvMB>L z4L&tC1nqB_Fzo$9O!Z*+$=M$MfkJ6JE58$mnQozYsdKmXsQ+!fPL4;}{i|~~<+~1q zedf%I{>NAw-&MOu{F#r>cg~@i$Jrw{$CE#`4MqJW*Fy78ux`=gyi^`2EqJS{`>f$!=`#Q`h77h;R9|DRnlSWM53PuA};h1qvGr7pw^> zWWOo8U6%O?@}m}gGoqxB1?`^G;wS$XxbH9CIdak|cInBr;FApop!~SdS+$B-^6OUv zSAEhqP$+O)RrGNYTXWPhquVhaFXyXcd{481L9^?|&+Liu&q%l?o@S%pxf3`xvp?*N z#nT3#VS5vLHus)``BXjpp!L-=tjB_BPF|56F}{&znjw%zt?IrajsCz zCZ9VzZ>voM#AD6Kp6?g4%ahuVsQ5??f0OXL#B(fR|I_P1e;I`Kc78o({W*5#Pukia z&*t`#afO}FvorI3&Sj2_MEyhWci4HJ%{+Q_LB}Zp@IR=vF06#bcrLde@aF+2pXD^I zpoFPUIC|`!(+YOV_Lxx@*w53CEZMOI^XIp4Zi6cq*wseAvH9Yg4#;nzUY2l?S!b3l ziMsEG`K@rgdha6pYR-Kh{Z*7N@AA#vNtf7_58p4fZ(xD=gr3^`^b&hnzk%Vt%FVxd_~r_mRBZA4OTnQS zpZZ{8z*UyBrp-cw1NzS!y|P8lRkpVNpZxA@499r7czpK9^WxB@k&!=H_uV0Ey!LG^ z*YjfDyg!vJstDa7_^p|9{o`}uPj3Q+vnftH1oh<+J(`^pb6I2K1h*jMThD3!WwAK3 zc>W1>e*YbUaj=-;S1c~E2}@~pu+I)*L9R{Dt!KqP-9lG9d(vfxu<~`cwY|@Zj&9{E zp0w2L5Hw%iT6W}&*j89~dUU(qJA{IvWj{rq5!a;;m?s*1F6)V1g^k*SbFQvs2=5>s=uYa?yU;pP#$>oDw^J(4_QgisKHUe4(Ak_Cm4K z+CaVShutu~mESz-UnoW{`SZ{AS#42&fnIa&q}a*0F6eAujBjJ)sV+$;#nrRs`|lsz z4E?j7_OA-WH6ixGh7Ik|{`q+$=M{*nE@wsh90)=EC-a&&DG+<#sCO_uDFE@9H0`T# zC&XPt_Ngbk1|oie_S4=yE*f7~JYJjH72{9-Icmc((O&(>zs!n9dwD@+OHUmYdmQ}W z`mvvEb_k_onv8vYMC|_OV5bGMTEm|CYGtb<;txrlx0j6>fcF0~`hMhL(Q|)nUdl)C zH!t*RpLY(4mdA!A#Cd3tA7=l}mj}gRqaVd@|3f(ZYra~2`hXa?#;zcALNnO8yS}$R zAU-%VJUOptZ}{{5r!k%PiyphCHEj7~XXH<;_$F?jxTpDI+irG)us$kgtod-S_+)un zy+u2M(0-ei-|ycejun^8*jN}0{|YB$z1S_b=o+?r_TXMSgcyV6W8d9k;BTUKUkmet zf4!pTX?KYy8-M@BnXT|wX!ZGxB}Vb7*0;sdO9PQVd~BUhMR9oSnjdERqd(1q4;JI| z#JjntU;km42IWWI*q)Uyezfa7t0rB#Aphyhx%akv-he!ETVcXrvI zUbgOr_Ez>@RP=*5?5k(_&mTmf{-Un}BEA<72Q{@S{Hi1J?-cgizeW5Za;)>-kh@q< zpD%6~yjgU+me8|*<6yKu`b1{_Ch?=0%j^B=ok1vn;raTW8%6Kv?`}8i=nDIfPu@@Y zM$G@smp_j)wHV#F;`aze*pNWGWZSnoV6YB}j=XZiX5*KZ>8u+8o54Os& zFm9p9u0@XDR@N7GdAO&~dt%0ox+DGjw}YLPyw`q;=ym(p@a=Jk?=K$Z^81F0hcbUA zz9GIQz9POPz92p)J|jLQ{zQC2d`x^q{E=8rd`NsiyidGGyi2@8yiF`4-Xh*4-XLBl zUL#&5ULlqeFB2~jFA^^hONi%*=ZM9`v&1vR)5Id;DVceN#FNAV;tAq$;xXb;;t}Fu z;vwQe;sN4*;y&VD;vV8|;x3tjN}hjX-Eujds38hOqZ8#5HAI1EbfkQuhA0q?4wO&S z5Cx*K4&@UyM1g3mP5DF(Q6L)aDW9kz3PhtFUZ5RJ7cpQs@UM57Jm z6E#GEXtbt$qJ}6CjaHOT)DQ)t(US6s8lpfnT2MYwLllTcf%1u(zx)5Smr74<6V;3j z)A~KNw{I4Rgwl4M{aKSIol55owufzuS+SF`ZoM2vf8(u6161P-qe-@IXg|pEIr9Ote|GNRMZRdgPp7idLE4ZjM_a~{ zkX!2Z`H&9I)kH3vsf+T<8ll>q0k-uz7qT$G8S?CP+))Z(v&t**CTWA_x8*^i0^ILX zxGJS9s*mpM<98Kc&g452hB}Uby!GU2yG)QWXhZ`45?Wt@MeK@9a8XwLW&2FTtJ223 z%>-UL3D3_gL)`z8z;yxG=3r!cws{yDuV!%m0D46F~aQ~E?YK(1-}Hg7Q~JToz1YhPGDfA;-C;o2LAlPRy$ zSEuIfRoJYy6eHs{vxMC#zyFi2E`3~E1^sJmp zO12wV;W`rX#8tbe%c)B56_=AUeIZx&+^iv|c3t1{uxngj$lqEm-xE(c6N`q}x1jmd z7S8pIr()j}KYOEx+Lvg}{uD=P@9)vFzZ&thn-kYUZg~Aj!6+Xze+w7;ILf#E(4A2n z#H;$uI1x*kF6ic|Ix-mYAVXGj45e+F?{eH3<)=49!zqSZmej{!#$d#YCf;5aO+9N; z+1lP>qWK-!d^d{9@;UjTI?fq#KdYcVQPjEyMbAq)qfx#p%iu`rz;BoC^EuWNazRSv z{@K)tsok{=Z5={op{fzSq5j1rgNLHIIIp>ox+77v5Jfi;5&`ilqXy zA0E4ku7y+c`3oPf`#2Qk*S@evI29dU!m>KVft;Afoj8;Fw*8c+Nt*!j-o0Mr%BcBg zeRrSR?})}LURfDN)dWscu3Rt%<$IKC7e<+1{_Xz0JhWfZLywX|shsE94eWQQ9vZLC zyAVRX{MrA~#0ySneKh;&giz&n8{{?f%^{yO{j_&5b&EIVce!#B<@?ZYLlE`#miX$P z?kGO)EKQPi|ZxMB^Xp()+cR@0U4{Ad{?u_~Q>mrT z&hLwq0LU2@qiZKqrdE17PiR^~by~=6!IxUO3Jib5qPsFz<=ujBs2J%ndQ` zhT9q7IDO1@G4F!g>EJjm%r!A5FmE?i$F-@gv=#Ga%$wAfXjEH8J?3?o*Wh;5IIarw zFPMMA{3DM0faBg_{uc8}-0n4wdx`lA%*%1RG933D^QV|U!Tb@9E5&gSFu#v^F>ZGc z$KA#J4(7LUyFwgy6Z79=ejW3xIPP~i?h59YFu#b~Q8-S8xf1j9xZOD%cLwv*nE#CV zNgQ_q#~sJ~DCS3SyTdr{5atIl-;dkv!*P2s-;H@b<~wm*9*)b!d^_e_al0)zZZqba zF#ip1w*kkk$9yg3*_iJ#!{e&06kEkk?9WqM0$b@0tmk5VJJzw4Zo~eq*bl8bPaKzn z_03p^R-HH2H)21w(%)eJ1{}8@>)1-yVSO#uv$2k?Vh#4M#(r$2tFXQj>npI1t#moo zmtjA)(xuqH1jjALI=0e9SkJ=xLabw}Sb+VR*pIDLf%Ocmr(+#k>3r-@!+va~^Kjf; ztfyifTWJc`=U_b<`>|CdVSgfy!&aJrbvf4Kv5u`Y4*O%VA6sb*j*G^66xOkoMq+(7 z_G2rJ!2Ve{E*$IFN@rqShV?M4W2*?o{t)cPRvL`;Agl*s9b4%PtWU>&Y^Bq%e=3ff zf^}@Ald(Pt>l3k#tzrW92Vg(8Qh%(E$ND&|V=Ent{eIYwt<)FC`Cxqv*0Gg(W8Dku zqp=@bg(voV;5cmY^S{%hfFRCDCcoPXe}~N70rETz;=07{>8YrRm9CiImCSy!;y{S5 z2jYYl@lcX;ZHA|JUkk*KX%o*RyKW7O$g=W8e3q7?LK0s2Y=@sU9UrGnyplYwv>AT4 z#Rc(F9pa5dtIg^}|0W;AQ*?><522S)$?XJ)A<@Hw19i^ zLw?gnHsY^(O0_}!k*JFL=n;r(nv`pU!Mp8d^P5H?9%h=S1MV4lGcK&A<4eqfx_}SS ztuG$x)9w9wF?4~w@1U@uIr@li>|LM>UM`ha)wX;hAs^OPp$BYkc!US%(c@k1C)Eds zoX>3=SV-@$d;nnpp425|7JqO=+-6XL0a(}9-9O?e&GQ*SUBNQ19rsu4ccI%4VRQqP zE^#M<;!P0uwk+=kTC3B4U;mI^FRoRdAvj@pzCx#xZeL<8?GEmIDCw28-IeCUi5|e( zuSzH5MjguU`G|rZU}hcn((zDwel6xwBM?7P>u$_EG2&&tvW>u(aA!ttgaGmS-c?4R zch5mh&x*mrN zDKY^&XP-4#FpcJM7EDu+=Edi!J2#coRn^FVndjN6`PNL{dR)BUKWiAG6!?k2XMhM4a8eV z7MKH;sU}Lan-1}ULbtHSO;RrLYx(;vKOTSo7nHR;zE6wZr2pEQ_W?+S-weSyLtdD@)< zy1$*ks2|w#uDJ4Xj5giBV_ZMbI*)&J@O?U;N~eN;psnAb${lsx5I^n0=nsB&NGfF9 zA`xHXrsxj}BdiWo+nOOBHWPoYBK{ozQf4TtDx)YE%Q19{B(S;@v%jow9cwxfb1dX z&Q_Sv{4<*|7$`p}QukPzqyD;a;rqcgfyVl82D%__XRjCxrmv_?dhIGgdTlDyqM?9&NjRl7Op3U+ zKVb#ZCwrw0GSo%w69Sl4VB(eY7v2q{=evKxBr8xe?$XC)o^-wgCoP5gfPx1{qM=$F07WVMnH!LrpdcId?PVt|HEQ&ts zjrf>i%A7hwZQoj9G7NG3k~QYk@A_+u-+hsb_~nv7b4sZ%xzhIm-9GL9D0AxE{%%dT z!^R-aeb8=3gu^01Ep@%Inzm{IIw1L7ZVV^K9u)n4?UjM<1ePvn04F4kxQkB7eA&t(@d3~8m{2vDd0$T52Z%3!e$<50rK(G|mwF;@Tb5x$oiq_mckq?a>sRJ$ zLRriSoc(AGJ$_92AQNg&_Tph9Tp5UWtN3C}*}k8Uo)$O&@%ufN9YqdlqP6LP*hi=o$N{p*aL)Yt%{8TEayxnSwtZn4}T16M0p()d`=Uy5ifj08Bx-U!`ieR>GhoOc8wABo4pTs zeS6XMaQtno5p}D}`=9ds>HQME14fipQf2e;<93Ks?|K+fTIp`B2_m}v;u5L{b)&of zC!Kwx5np*fum`pJxwqjhPkMc`AGCL;94<%~GR=q4{Nax7)LzTQc5Uu0O4Pm-bf@Mo z=8U_shC}!FsLYTWoMy*0z0-tro5wp0sq#}<^A{|o^?^@-A>}?~cC>*+jCl8_W!@^=U>oifPEm7ww?=+h>EiQ9HICW_vB8+ZR2jx>93iO?jpgkIRF4DYJdF)>{n}Je2Gse*N2~W9b3?q#i$DWP&!2N6zt#)!@)zy; z)cP@Y#~fybguJ+y6pYHDstk#tB0i$Mh<0CG3o1sg2Z@-p2y|*jk z&2IOyJ!)~QQDGM&HteP9>rP3X?L%H#BSHXqt`sEzhkdc7}t z)A@hcp+m*rHEt@qOUJMK2y`e>-?ih8?6E{#`l(Etdb)atWe*((#6Nz@(5AY3t$U_< z*BbF@pMf@&S#)sTZ$jw#Ykn!yqVlROT@NSI^|SX&h8E@dZjNB>IJ&)C)gUd(y)kh1 ziIKw*e^EtgQb$J2{^<0WUjMYOftpm;ph%rpnRI;{SGQ|WL#^fex;c5%{Z;SKp!Ajg z8_xEn=ij9!P=o4ee6?BA-Iw0Kns$PEX)!Q@DzreHQM-en#LJ)0C_U{#U$3=*pm@WA zMmKF3P3QlfYFC}|aJn$i%pUQe5AEMnLC-&&vtzMn{Ui9M8oU35UU!Pl&;L_Ko9Y=k z!KJ)~UJsYgRI6&tofDCw0Q&lV^%=CPOwDpfTK`rP@#|kQT2yCd{pR7V05^L4Dymr( zkduG)`eyq2$okseq)Ni+ zph_*fYdC5%y}m!yw%4n!=_Yo4=uhwOtU6Gyde_Hs;LYK1eb5{3RGn(>>tmsJ_WK~d zp}xIVHE(g#UE3vn5hoi!t;&6|g#z?+quV!R)Ts8(x1ICo9nBSuRJE$xoa0#+XVd%F zyQ%%FYV50&cHM!!==n5(ud4bBOKpq{NW{6#8C9zNuimZDZyt$wTwTT&Rr*s^z+{F4 z9bcdESygiR?#(Ty>G>Enw0~4BShTf0?hIYujSU$eRMF1_MlCG5zoN$WcPi`r<$Eim z>HPDWGTy3kDqn4@dhAWlx4FGi<@N6KWM%=I-tU%-*Q&xD@mGr852DwE(JTS3vjQ++L=77_`Tsdl{g4OZ!vR&6b|7 z4rvDTdbGAbQYDp{j9IGCMO@m}{y>#;MEGh~0bT!9ZSBP>joZ!Vg%^2r`)}<oiX zL1hZu4|sfQzp1KT=p64qPK@%nMmzo^=4>|R@xkas-H&-^x|B;yMBJTYwJ-pi?y(32}{-2Hy0bR8qyob4V^ z-+#Wqp3`!`!MqBbzIA5H@Zhavuwss6%g8D)U2p36h1v1SMHw+~&77-1%Ax#m znYhTT_}JtsAUm0~`$fVk@_GHU;gNAwz=}NnqHOI-<@K#ey`KF_jL<3YQ1vo>OI#tPx%V;4}Cs6Te^UpH+DXGM*bBfEq{2{ zF*{TFe$`4r)AFw%vd5;o7Dj88NjGCZOx^Vryqe`X&wJ`>vSgZeR{8m_K)2q`e)0Gm z<-xPFSW8O20x~S0h|$O;2Rv#W;`iw*SaEuu=H{}s$_Fb$mWsPngAG}uGn1~ZA~!yr zzt(e5HTbk=!-n(&3rImoQp{XIHIVCEJC%MchXi|1_}(5{4R+Vossb)9C!eLgkhw-y zgGcYAIh+d%$js2Xin6R~Fy9cY6nSq^Ry-e6w>`HS1Q;Ja`qp?cnf>T-QO22Su&b}& z!BYcAWmm0Ndl%iS1|^P9{M|LP$qAz*2abNM1`93jyY{#dPnw-(8GP$f170m)-J4yz zm}HfDx5f>w0cqO3SHIb|oNPA_JE2F`fIX9WS%aBYvA|OPSktRM&-;>o#-PgYk*Qahg|iWTxG+K*W4%jYQT%S;0L@{Ny^vzO)lGB zt^t>aPvwss)=<17AM7mZ`K|796DKQw#1WzG%OoE<27GdyT?>+zhu!ts zu#GGtFaDgrxE54}WS`n~F@bzu{IJSqS1p*Jx?2-+Gl#Uc;oW~s)q)pJACGQwo=+M+ zYs)$Dv=(quW-Fh3+)VBpxjp$rQ!RKoaq>O=-)>Mk&AgNU*t`yWUVkBCQSut)0^jWu zMsVxEPvr3ds<{efk9E^;>>gVOw!HrIW!tP(%E#6}^W0;hzJ7ql$n!a5+qF$4#;fYU zn*m#)IYZVVPVxs;`VZQC1HQE+yfwQAH}VHjHhW-(C;uyDuKvgIuai4E*>uX;1^mnY(nc zdrYP>F>{Z{7SI61_hnI!_Gc@9AMP~aLtq0aj%H1qY?-YD)1UiBC>p>>b4`OYGdGh< zG(IGl?rZ>~a0$%8KgRs7xA6`##ODsL=0yWYPc=KIIX#Xv?kn-P z)@}qgo1#M&r>#?(-1g2{Hnb5uWSf-?@ZPRGe9gkGuX`hCx#hSk>%mgxr*$q{AI)k6 z=juzgHeTJK%$d3T(Y57`K=gB3&7}=FakoRT-kEa%AAMi8~>Wxh$_BJyhc+OAVgn}Eg8Np`6Zwku!%?$$9rzX_aA|2gwo zV7Ri!xa&7vrZfRz)t-%MUdc*7pXWOk%x?lki~6Na?Y&)jPWMLK*SsdcuDreWLc&^Q zcGa#0Yp*l`RdxI^x3n}8zUJ-|`nCzgcvq&}uuLIkucyzO*{vC{@AseXIeER3V>|le zR%SCe#Ctk_8gnB#eW>JwRzNeTa9s5yX4H1&q~9`4a#NeZ)zIJFNWZz2q}oygB6FJo ztF58?@0+v9xi!U9PdJKi>f%);s1TRS(AGf%A=uG_r@SiVwt z*FE2=Y%%jalh0`Zx(~CMGZZ08(d5^w69^2Cb?1uYyFK*3M-n;0PJ+QC^WaZkJNN4^-^^UkZ+3wH`;QQ+r}+= zwzW?yc;?}^OlFix&Mj&WJS1%e23HrB^If-+UUw(jeGPAg*Oy28n5FB;pWk%Z5WS`q zxJ*-cD1VA4BeK6dWt?sWPdwkY@3_v z%vWwxRxdNuTQaH*%vrQOexAp6<&xbkPkT>l16}x2A8LMDKyF_6d-IoyHt@FW(~64& z*D4pWpJ-JcXanq@qaz55ZDi0%jhey5ZQxSxs+5V3*O7r+=W#Z*wt=Z$y?t-(S*skr zv(D7b>KoW-Iyck$)Fx#;Sn;ZIm%XZGRD z8ORz!glQ5)|41F8|70CnJ45{A$L?$$Bcn+5|I?&BR@|LEhXi(iLep#Je(896!x(*W|2galeYrb7hL zc_zq1EtxDjC+JgX{Lu$<`19i%{A(u27Ge7ff4D@;=tuhYrL?Y24W9qvFZorwxy!VS zav**kSNbcRm#t;w3DKFJv{TDyA;gdJa6j64yzOxwG=!ANHTFrTxQr=N=vPGvDc7dj2?mcaI`v`$;+ck+I8ALtoqXD83wyTAHh+`0b zb?W{V&=x=tEifMl1qAfdpFSvpK<8D^5*qLvf&n3gsDg7D1=mRoF$N+SLJqM6Vi&|& zh?@`(A>Ki>L3B^jAuJ$-5MB_W5c42%AkIQOfM|f|ldMDVA$%dCAyz>ggt!Uu38L#9 z9l{#I6(R;A2ciJtF+@FtQHl;R0%8orbck4pOo$B-Dv0+G#;H2Qa0oXD8AK+;PKZko zWf1icCUbR&Q4qcmGKh4D%@AiGiXq-Z5b!zF9|A5Ap$XSXo6sS;5W4W$u1^>cUE%ZA zkmyeIAdHBfgfU?PpJQf(Inj&gP4pr968(t&!~kL-F^FIggNY%81^k|EC}Bld6T^t% zgbgu*7)jU?cEl)xNw5eu!6CSWJ;5XRgn$qdB0@}%gaaWV03jtD2`3^pE-Aq-EGmjV z2@I2k#)ip$eI5w^P`NBPQTClLF{*c%t+_0l#ZrIszeC+KwKCLIq1jmHUi3m%a)j`2mROqbWm>5}9!e7#6%7de29hHvP;r9~uLl?}2j_%L`uFH2^ zo`75Y`P#*W!uiF{ObiT-iipE5dF*UiXd=3ff}=ws5@KT_LchO&|CW|`LI0+7phO4?0z4Lj&2Axj^&$JVFCzI)L5q6?=$W|^>?=Z{`M&Ta6 z^Wug1Ug*4|j&<6Jju+&62`|O>?%1SGyn*uIm~h+?y87USC&#Z1e>oZz@EpDm@Mi~p zy_g8G4q`9FIfw@kRS;d~!{<5#55gNF2tp3A7$O(qAjCO{8xSubnjwtSbqEoJ8-zbZ z2t*XbT!@trxe&)7R1hT)?;)BYx@5puh#?Sc2q}aQL=Z#_#9WBg5V;V?AkINtg}4Xt z3ZfpOn*zo|kPs6fWOVeGJ=nQXmvY13ad2FZ*zMx*I<1dp(N5sII`Nc&n*78iiBv$SQ z%PC0?MOgw2BgSZtO_Iq|{bcf)vGVBPm{6HBymg}9d;fXwo?%4)UwQp!!P*RiPU0Q% zj!#WUltueTM9Ul#V1_buMucj4!jg&zj)E04-W%SbJzxlt0W)%ug(QWC%jCagQbhNW z7%Wdrit~(_89R|kL7p+OVM$Rk4|)YA5=0d24`vq?3#%~9Eh;Ht7TqgRtUWFC=q+#z3zO43dRfamHaHCHt|@R`LbS&PMeOmN(I`kOZx zcTc^8Ve|k{_d%Slgw!}0v6yghzIH%qG8#?wTzKD5)V6iV836q#-Q&koKh2I{;?Ay!eq{~g5|_FonKDTK9h!`P?8gwAmJr0>cYNQz8-yP5-+yTQl|%EpLkl0@?{nT4Z6l3e z`urPyOr%(^WAxADzZ_>a|H;p&);7wk(Kaf72j2_qnyNBm!FYhrvzJ6oJ zjrR|jFmcl4Da8NO@&8^2{~P6?p{cEh>~1ai99@vQU@-RYEmPZ_d(<{_M|mr<(sTuF z_rvxVcRk+K*=A;bQ(GyvKmU#G9kD$H+uzB5mEV_mo&Pp}YUll@@1)Ph>Oef6@t8pb zKA!!U{panAOP`lF!B;owF!EPFchSqyF=Fic>&U=IH`v}1^3Grf`-D*U|9^XE5WV47 z2*vk)P571h7ySC@@8aX1ZO{J;4_y+ZL`O03JK_%3EIXz(gMQNpew*%K9pLX~E3jrH zB*O3VgQH?&WDeG;vIJ`&F*G296B1<6AyKIe*g;H!gLRTTMwAdbOBNlRU>h9~Dvw2P z7}|!$MvHxa z1YbF%Vh%lWS$q;4MHc2Kk4T2ELBeGTSnMdfrohldn25J5Sr)~JLSG%MgA+Vsl4B!f za%)CXgkvatg#_m|GdLC2oa4Q)nn$E}TdIwyHYLfVWeiA<`AOi{eB@VpK4&HlPV-KV(njEfW=s{YZau z5;=_wBE!g8WE2@kCXy*+8mS<&$fe{;a-hRbhr{5v00zO=lcuOo=6arrcZZk3heV+s zCxjir-p78=-orb}i$VTuwV%NSTvK~z`?2;j?f3CU@`*h7ejfDCX2vta*pY01&Lqw> zP7o)IGm8_&iQ^=4QaEWG1?ME^3`fZ+;9TKc=M-{^I3=7?jxM*sev>H9LFI7MVS{A9 zLNVUX*e|pc4HJzNG2uF0hp`@FZ?T`4C|A$nG`E+?O|(R0DBdVOjrOEUJ>ElB zK8M2%=Uw417Jd;;5ubP1C6R)&;3D|bH9d{x5BEpTeaC&nbL4MvfN%d0{n3~#SN0n= zpJyc;EaHgXh}V+)NrIt{S;98p`}0fqr^GUn0#^aS)Szo6m)XF33gC%UgK&XnCG!UF zF3*VHmtVpEz}FC@3pNV&2u=&`3tkBt1V==a=%(m`_?oy}{88M4>_>`8Z*n?$gPcm& zhXx@40%%QAttRt)oEDJV=?ZsZtKF;>!L~;eS-FaK!4xkq=>M{8IbUtxRy|%r0-S{?0D^P1U0Q^#<)@oP=?1Ahh5~5ta z?xC=D=P?&Cvsq@`!(6F-jD4Q{A^TJISM9_3$N7)=eFO}FwZKl0B-kXlCwL@yDX0>R z6wVMX5uw`AAhtpC(0)GeH@v;Pv%C`CD_$*6i@!{mExahaE^LB72(}lIBDp9P?!-~i z8_{RcQ1M9dRB;HbzwP3C;zwd5vKQ$_jv*Jp>+>?)(UlJC9gaGja=7F0z~L)gdt*r- z30ESPOpr{Mq)0L(TO>OrO37u(bIEH70d&C-FdP8j27WXT%I(&Y*Sx@gT9@bd@Iykeea8}JCB zQn*5V2G&l6_?@^;%ph$@Pci^jUIe+CJVn|$1ULjbC>)kLY=CuD>`?1KNc1G85}_no zau6s%5v+GjA`$HYvy3^2HG*Zwk#eSU=5Q8rvN@YLJZ^XUc>7j+OWq7#5s%By=9>um z2zY{i!errg;bGx#g=d8lk&CEMjI;QCCLY?i1b_avIY0PsLQ zI0nuDdatFL#58D}n4_5itQ1xms~h_(TaPo2vjX0Oo^tfLH@FYDFSwt%3+;b`yLORx zlQ)$g%YVif2;2lq#e2mC;@^qy($`vx*qj_jDkLu@pCl}B4G?~sL=^0M2(ve9G~16o z8CGpLdpYMNhvd4!y7cEx;eNE=#_u8+DDV*Y2_^`p3Bm*~1YZRHVi)otiSFsJJ$)~;nGtc;Yr~&kp}V? zsB6fGYs&4-?ayU!ExE(EBe_g2mn-0sTq)Ou>%sNr`oYzo#GS?s;)Zc&aih3#+(d2) zH;t>{W^tEtSHdUjhCeiS^>39;QTUAR5W+xq+C-aa3vH!sw4HX) zPTEDgX%FqCeYBqr&_VjVcwBw0*3sU;GAT{$B#)B1pgvd>Gz5)7B3db0J<5)%qq^vl zs3Dq)R*dJx3g}I^6`eP-jK}dclm3)H?R!BYNDnfCWRMwb9n-j))v_zt7yMrHh&j|A zV*{t$VlZ|_N0#v_@UlC-jJ^=v1>JdwJ;q*O1ME#U%syw|upij3>;V1)|CP@X%ZV(p zzQ`3@2q$(ByF%|5i7Q2uxKZ3A9uSX0cit4k;v+F8)>A|sq^i^%`V46P8F*4!N&~N^ zyTmug1I$a#zJEVjUn~2y^>Sw4AH#?FE@BIwC%8iaan zW}Mm06q_SVrTN0*7mLzny;7VnK9j5H9a26uXuY!8pMNK0^pa>D9;xf$>PI-QDlIkt zZDRaTo92z-#gKi1TY^=?jlvLG@lg0$csxCiUPYgzTSdRbo3ap&x<5OKoyO|ev+QNK z<%&=Z$_x3u{Aqr^=n?OTRb-ajSZ*PAkwtP}St<{c74igmsys{9$%XPtd7Zpj-YM^u zkI84@tgp&<*I8@zD+L$hn~@&>96%lCfjUc z0#jhlGYd_VxzV(m4zrnk(SB*O-5%}~SBL4|?Cx+gdFx^Kgd239y9xKBoAJUluLdva zWHoXIxrp3FF81&A@Av!tH~e?}ulzZ|vccMcAM6gq4I)|04Ob7Jq*L?{nuyY)j3^l$ z36JWCI-{R;N?v?{ju)*nP<18dFgY& zd9n?dxjU&Mw?oNV{3zHqI5<243fT}o8uo|6FD zaJ(iQbw2l@@_X_F`BA)*pU5xg*CFjJ;rH+X)Uutp8`TVo1ae#`^W0|Wy`eXf@Ue>H^);HYj1V=j59B0nNR9ehK<{k5cS;i*q`gU{c z?B4cud#XFzUEsWqG_NbA<0p_BvXHbuqaGu@WPps3ugK5jce0xQp+DyT;->|BLgf#K zi=Gu+9^4qb5WE(MaHnwpupC}`b$CbkRCorxh+Yd-xh#4;`ZiiEK0UrDzAkQsg1!-d z7H`yq=lw{lf=YmaIzFBAbwq>_`qnhN&g(sNg9wO6K^N_*eVq z1{Vg;2d@Ti2OkE11j~g-ho^)WqGv@*qlsv*1{m_AyiVPW?%%5(R&N1k+v?r)q2R{p`Z_(LS1_xY zZJ-Ccngh%)X0Bb)X4>76T8_5WcA;GYf19wvZRd7%#qJz%(KA!@b2(FXu@;YBwh_a3_lIO43qEz39Rl# zkA&LaLSF__R{=&@v};rp?Gv38T@x*d?g3w3iQbMrkG_t+k5-P?gK}>b2k~xkX?#>% z8J`$m9^V+>8840RPvyAv*tYBl^x|B$h~3YgVXv|en8%lcuT#D)-;o#dOZb|Ch)7hZ z79_c^)Mol%U8P&~b9zgo%-)!5I&fEKpR_MxnpeBUGxd(7c_S(Ae?rDdrhlY=t^caO zX>fILSFmHaA$+Zf9s{+zm@c8O(=qxBT`tOrM6@56c2#t1)PV{{qB-#vv5WVF@0=Fb zBL{TG&&2QG%*(M=*%oYjR>1aTO)Q6R$|JrzKa-!wFXfB*ExZl-_yRv#oFXm|SBRx> z*yqL9B9u-(F4NSCN~;~fuZ5WLL#ju;s9sm!s^8S=I$Ljo$_A0VHZn(>Q_Q92YSU{* z&7SsmyNYveCwIGB>IU7E^Cr?#UN(nhkUhYxcgec`M*fZd?f$p^q43ay!V`hQD=@euvoW+4!rVb`=0-hGSh zL00?GuIjSgUarcW>E3Z4x-s{So1U3*GLh=RZe%aAA1NirldUo37Qf5?#9t#gDmWpy z2=l%ncmSDv8+tUd#PyhKSClPsu`QJ9<8`g>)I)lXnQsJq^;~nMnZ_P)sJ+PEWXG)U z8r;h>&&f%oeB@)Yv40pC|DgY*|B8P=urOE>bb~iz!Sdm$V9e9uXm|)Z(N15a7ex<6 zuSSV@!#FQqo87@y=j-v~xf1(`#Zaa$@rHO$EGt)%o2T~YgJhGuNq!^K(1}j9s$Lg< zz5sZ>&Uqx9y#-7r(f6i_yMMSljk~+MHx7+`xVyW%ySux)I}MGyyF)|cvixQ<`Ooak zZZ=cNNl8-oo;*2Kb#GOj_w1#VIh(^ff}8~y)gA)A1itvc@Sa!B2Pi?|U6GIwV&P|C zYhi4^rC;{>`ury@!n_tP%h3crDW>*$Z!cbCy$SeUsFW*-hJLZy%-XMXY?z);$rigd z$GjWA-+vqhTEExoKw}Kt4NMH+tfFTH@&-`_odm8lP%A*bg~kP2&AXhbJ8MjT!n_*1 z6Kp6=d;87tA)DW^e$WYSCmeFs5oZtPM!UfwbgRZa9GSh$YIMU{ezBE$C0o;V5L@MIoP^Yx~>N8xeQ78uTo&C z4l4gr)O0mE9rjXMHND&{Nokxe%f_jCh3V}d&oun~P+&b19o&~s-XIylk@$L5~vZN^;X4kr&4IYnCpj@Zr*g-3D;nKuBdZy#W)5)ydZ*{nG zO%{@tXKefi_tBWMpE=c`^~~0AI)knC;GCTN?JYPkVS}ib(STc|xY7l3M|Y&=NF{}P zb5ORb;8YSPjR1$1@pZ)UHTv;Yg7Fpp@nvx5@K~YWl&9$b3Z2Q*>B`r;!^QX}Mdih* zDayku<9}Edd6HjHUhdgYt3QbO%n7kUd{^UElo$V%O-OZ6%?14`Z-j)8H7tHx+t^N8 z8(DRr{lf?xy@bLxD9dGp-+{<=s=%F`Fp6rwV%7MJZlX~$cS6z=&yj5Rsy)j-$<{Ko zhwNL15v;esKsr&nQHo=NqytD;AeQ89EKh zAycM&u@gbhiu3TG4WA*ttUDq&EjvJFGlI}{ESGadR)6&V#{yj*Mx&AXGI^d7S)AmPjw!mkrR%|fpwyM6U6Lp#-C+rf!_d9Q6SupoOH(WKcxETkw(fi zlj0?s#Fk zfV*Ae#jtJPPQ`BwrH7U2XE6r-*VJC&rr|aI>XQyGagsdy5+iVyJ7Wq zl~2%GEVyEx`OZ=P}ssa;L!bksP*Y{%6&!R(M&xzyI{x^UjA+=1uak$GNX@Q0|B;zq!0)Jk^gXkkjH|A z0EF_PA1DI4@$+MUAa!Guld2U?{)Bv7vQ(=&R|9u$hU8gKnExZd?*H3VET-g+f=@3$$~l5z0i#n!<3d}n4$nEscFv|#)a{ILs|-4Snaop8@s#>1!#Rmf zi*jt56+%Zem)buxEuBTxuu{(DT%rn8M=#1ENWfK?=xy2`C(t!cxTj2|O;`GdTWpS5 z#1Y3V<|^stZt@zOj!BhGO-&nOdyeJ6Z`ZJ^M*h}Wq*W4Lu&3O5)n%tMhOmRe;uHlRcZiRnxhY=p8e#n(j;;=8t7Ls z7%Goqkn^7+lTwhbU6v}c=hEO7gWoAVJW^QMoyfd1C^!STtiq+?CuMKaT*gS*bF^7m zfAdGbRj-eQSz|p}l`gy&wIHI^3TlxIEJ0kz9Ue)u+d$3m`#ZWTJ1Tge$rV(B%Q$x< zz};ogVs%cjUVaU2Cg(jt00OWmhqB{?A^kcwr}NOA?`*e&_$%U`jFIsVMcc!$gKXu5 zxJ&a1a;0Ey{GRWqlw`pn;6VPfF#PgWBHNzuWBT6yk0F1XwS|$Ly^9kA(At{82FPv- zWCNPAaWZi*adDb5b8@p80*yJ1Ik}CwS-7}?%-qDp42=K7DRBSQIHG~CQpqO%uG@E` z|1rS-+Bk!gg;}@@1PCS!2mvMuggskqxxI-DP=Y`thupG*hL02+4ifBFzz{bG94yLz zKe8|e3UWv0sWCQy3rbmAmxK^$hYaG*uVYh)7qE-oDPwY%VG0T|_w)o>ohS_5umKHk zd*SxNb(0hJBjAx-Xzvr`=<65!fBE?z2zghY*IeKJ{l`%LAAUNS8!~fov2&YpGMNC` znK?~N*_gOFIXHnvCMIm`M(jX#4ptKu6H{hGW{&@N8c5$XW`z}T{yPoy|4lFde{t~q zk2p+rKtV3LJMk)#O)0lAsk&2=kHBeTpiQ^g)T|aO3l9O_PGq1UIguF|xd%z~O6&;kC%?zkq@?9H5a>Wk3&R2x9Zav}~^`QSA$B2Ui7I^K@+Q zj32}N&ye1%*I%{2U9|t-Lt^D(LmZcd0~1Do?C&W{2Sm@#w8bSklfodv?SJH$U=-y@ zc{{K}z{)vrHfE3kYacX)BC9+~EXLc*`LIjZ^wvehnO087{8436s;ltZKe=Y!e2?Dl z-*Q`?u8{vLdjA6rzNn|{{{z~$C;vy#j5t6+vP97yICl`{su}SO1b+2A{_3u~fvPI5 z7t|;6+mV0M1o_eupurZ6bRs6fz{@<~%_Y@UkuF~+hdn~9!B5Wzd_nyeG{)}>&3a{y z)%F`${Qn*rJ2MO7^akt@69VLSWF^3=Xf@LBIH2?A8<-b3e;p&(d&(kU>>0WAZYFw* zQE-|ffX%X0tBKRf=*43u?KR|wa_kRS^c?;wNbME5uL0H~^sl3ta(~3iZ zz_~n<6n}}Q?sl`!@kxIcp40ilEfLHvgKeGhiB16sJ){O87fspn;{yMw>8N@~4Ug9w0_qH7`; zaJ5ZG7$FTur3)m52_&{eB@1^$xEPJbVICTHm*)%3H#IsA!(J;+WV5(8FOpxExmf!t zo0!UBQT6XdV20a`sA6m<+WF=_``$-z_M_*NT^}YywBQfJ`&I`4ZVQn3Wg_zR>9?d- z@CTge-#v7w#I@Vy+|$n%d@pCKlZ~CU@t&tGJFgqOofP+bJY+&|H@AIxJL&GH4`_g$ zV7j^I#1!Dh(``&A_t_tMQ?SCg`_ynwf9qz*uG{+a7pC8W{?Plz-HO1c&y+qvk~E83uR{`0)0VNdB)HSFSDu*a74`Tc^S z_k65CY2uCjlh*Y>{!4tx>IK!aCiB<98{>$}W{Hme8}-)uKg&&r8^5L#ho=Z1&&!Xv zj80Ah7o!0yLA`RgJD0wW*9FPW8!t2E8I}e&^7>|8_;iq<^cO*g4rBu#Cyh%1<{SH7 zMronmO+USVvoLsd4?BHtYM)M(f`Xakh^KvgAymsET%I$w_C3becAnWt={GEqI>UVB1ymE zqL61HM@~~XFLz%oqXF zxEoe797j4yu+f>};$dUPn!2f&ZhgzZM} z%SZh``!QZlioQQrSP6-=K8H>HPI~&zpJ18WFg)_oJ=fjLUYRhq9kJgY;1rvoB;D@mCpfxu`aLV{v2SE4tFWbO+?(n7uIrau%Xrr;nNRfZZsqo7gV{x1 zeQ$90&f(%)iOO;kAgB8mLh4Q&=zYO7vU(i!H3zbWMxb^IIe6Igj{54@y^C+tB*ig% z$Pz3z?ZytLqDf4S=+t%MmU1b?{!x7~JgKO8tH%-LTdATJ#qq!7^m#AK-%L~0ei$67 z#zoSdNCN-)@ZC~T67{j$Z}h!HsNVE=+V^pu{RW@WCazv4mD8+F^@n|;S`ahl17l-H zIhi#O=BI78dJ6IlhTvSaxrc z{-_H46Mj9tPT=`8Zd9=0<&W`+KAsj5)8erz;T_Zwx!*Z}D)%)m&3oe_X)dFn`@0Ad zi#~PX_(#53KslvE@?T|dG;CR~sP>hkCp?8rQ-RC~595%ihH-b`g8r_9!b@8~gzkGO z=Rup%zUs?1FwBpKhfP(jU5ur5pJ1Ym!Z-n^4{_6xl`qq}G$P_YToqF|9W%3+Gh?`_ z#i1P34o*b2Z|t6|(6|44>Z?w?<-r}Hf0r6Dzn$&J8aFk!x3)eQVtIor?7`lM_#yHM zQ)&Tr)1p3i;jtg>QKv`_<@Ro3S9%NW&p~h>D~Sn`t$?955Vf`Epmc{K&r#Ln8JufN zN4EF-EsA&$h5@XVt^tgTm=9CSpOm`Z{(%+xIV%4zsPgmBpfa@|tw5%A5qk^e#;vta zH|H8$X*UviF$mXaTy}qb$1TnA`S=0M?TnFY_RGe0%c*@pevCEda`->h1bPG=CJt^Tq_Jv>sn-Buh_|sfRx+;FR?^pT&6K=DTh$TT zkKv(@w#KbIcEO7N&`OZUf%$arH5`g?1))o z8=vM@%4z>8(01u##0tZFQpgn5?kzBz0NGwTs^0i93Zf^6$z{h;B12K(WM~!KN$Kq% zH)xA`ZYj+;DNO>+?lgOlhQHz+{!?AuBDo9?O^Jp+^Wsy3nVCZnDo*dAZ2>3HXOBM# z7hc+mhLWOVTh_x=i4{LR%!`54(E5W4#jf$Vv?`4DryJyF zF#my7wl%oT0u_jbb+y~(y|!Z=zhD9}G*^Lwk6sze50!2uR@tLw*}cP|GJ(Cxq{<|3 z48YL=$@7mP!Cr6z*4%R$YBns=&uecx1pYIkXJnlK^AUpJLA}A+!zruK%)en)%?S`# zHIVv}i~R8vJFy=6WzxR?>tJ50i~i=AtE(3nukjK2j>z#(@g0^SWI}Jrg@;O#sk*q zOjGO+t(NB8CI-CX{NSs{%pqb7*GOaNUmQw<8v13Ik+$27OKZrTwGu2IL@D zY8o(qDFU=ZBSvoYqzUsJAE(Dw3Rcg?XfQuVh-cc92}>Ws4Si|?ZJ_uVzinme4uklW zfksSJi{Kb4Z2L2w^}A75O1DH^^^pw;jJWRs=DA_Oq+<>n23cn!ZmsgbM>Sxx8OAmU z#uh5C@h_#AC@ z)2*f+Xp?G0TQl;=iJaw{r&vl0g1rLhJB{GUA@S<)2!p8sr5aecQ$`#hh#|@`L}i>p z#t!a*hMRQsY*S(th!}zmi=q4IPA$Sav3QlgS?96#%39J`&&vU`c3gLt=#wrO6(ydC zOWFGvw&mv1NAy;5eYbhxW-Wl(E%AM=>I8E_HAzGn$zSP3#&#@I=jC15@)wJlv0PR> zL=9daQ2bpuy`Nl8U&0Bm&ws0;)ZLAt_qnj*#rkq@p!zkvE6hR0Zy6! z5)q0>?&OrP_fXcI`n|JRu#fqS@FJ$KzFzy!CG(zAP?nKVIy$*{s z>q3JYK&p}*^|a&k_9sFDoeH0OK4H4m{fyYm%b$P*dcFsK?S5iK#a`v^G&-7)3(etj z6gzz7F5u|jzxj2Mp9IX}}Rz1p=Ttc^>9>HN*t*eBaBXfaH^ z1|IZsL~~WlwZ;JuHQ%e|_F&CTLw(2;6?68y3He3p?@;K^5sZ|WE4QUVJ`tht!BO>K zef@%6nnXph{HJMf9|8U3<}^lHv_|;o_3kY)spGo_ef#+t5!*r}qBNaF@-_0X#E}xqLfuT z48C5LBrRf$l2v~|Zp#`&H!Y--qYymAn@=5tt3rxJ@?{u!FzxuhSGYf3%rLitjn z?Fm6+kzxt*bYYrqRRzOngq8WI#8aDRQV{vx;F}87yBAe#S4hoFFI(LUz=H9%Y6X+X2-qzI%Tmr4pwSW}`lxQmvji;$8beP1EEC6KJ{=W^f-<~#LoJ!^==c@ z#th+h?Olk^7wnQ7EHc2SoO^7N=G1Vf!~C-k-w$^o1nu6u6)B0#Li1BlmKTo5P*T*2 z{KUvtW-?M_YL|-D92UC%$*0hIkfIb6`osjxiGDzjrrfI_D*TtFyQny6R~h6u5o*6D+3h63$qWQmChU(Gh)EqBm3++|mYtq{|zJkvla098UZ z28x=#aW66u^WP~o$Y8N_QvE`;Yu`9IKH+jy@vH(94H7(!XZ<1hpSi+ub66J9c@ol! za49s_KitXsiP(WoA9{z$U5Dmrp|x-M%>hUrjXB2m7V6P`Q59xkey~LMnNRR!&P&nd zqjYqnQ@TUgf10})&k=Y`%|o)qe^if9|G=`{<7QogrkVPZx{22s)9umRd=k?KF6~y0 z9ojHi+9sXd*BwiSFsea{Dhuz#M0W6qUxG3gLj4+s{Y%Q@(|Mb=K5o&MGLPfm0SlAu zFM{s+Cq1V8FmN-K|HCn*`lOk0rk+YMG1(yWgV~Ycx(o+gmkbL$PNrN?T2UG!;&igq zg_OrRkl^G1RV=b`pSd4-_IL4)>4cN3C98TN>ovAG_~TIhXxk}B6$0MQKA|!Z4lPfH zw@w3;Ja4Qt?O5^6z9ul+c|yv>QObFJYylm`=kDh5`m=UlD1>F+r1#&xjd zl6jn3QTTSwKSTO?^@&_D+w}DrX=0!f3K+Cza)olS|9poQ?+?`x3F!K{g4J=*YkZ}6 zBkSG9Q^wBofBUhMOxF;o^T#OjqcAwkFc#n<509W#O339RHZbQ2P+?(EBckAV7zkpmnC;?}q&k*T{h`g}&Tx5t&*!dz9lh%Vj$X%K9k4BS1E;-g9TirtVFNGe3d_e^S$ zf3ajdXO&Js-9ci2=u&>-hvt;jgY(#G-IMv%XVf)QCX8}#W>K6>0ef*fest$q?TBWk z97D9U3Z)0fJ2ZGIf7*upT6E4Wmq_j-aohuaq?OJXkzA`vhU4n0Mg(~f%QdwGZ`!1c zCZ%VKL!g*x0ke%P$V#Ug`kq=OcHS2srnewv7ts8m$RX$Ar+q>AvR6b=b8CS^3kH)RYKael)1=4$$4JIf1hi zq3OohMSrHy1?d}=OM_9lGgu17&h;ujjVD(Cl*~r@FNJUx_26@v&ir;9-%$9Z$B6I% zsu$^G4p7W1fV*bRM>||`o@8=&B3?2F=JYg|`l;@JHOA9cQTRfbBlxBc*g@YWY45sH zdq|HZg)XyHTUzMs=H6}Fk5 z5rchNNY2`VQnO^=!6*eTmz#doU&1cK6MUABZ|ORlCn8Q^ANAEUtP1%rgNmuF9s0!NLW_i@9J6OX9;g?%$&5Ac%v00WX?I>9lrmc^=; zQpe{P3!wd;WVgT)k#h++%TM%1g%9zpyLD=*C60yOR=b!Jf-wl8v1_0<4}ITKEeHhD zVX9aoO`{%U)1EF!N9nFlUoj2!FbY!zGQ;~th?kPaPccz^wN6mNl>bgvNlMRVS)~3F zb3UbUx?s<5$@F23DrX3>k+AREgiRWcSM${9uIW~HDJ>LT$=F^YO-dAvLrKA9XP2HgoKMxR70}y8OLs?Nn@;@u^gMs!%un zi@KnzWtK_Hxx`ukVugIveawfpeDDxmPJk6Jfk}a#CLUska9wfh@GSAV)bBv7nYFhZd(Ksr0IlAAp2#Z(+&BPn7v+lITjsS=itH~7v3*w z;Cu>q2na$LzJ?N*n#vRAsKA7g zvy$~%FT=wkp)XY#pp2N3{aGpo{ueH*1pnyaUAjE#^p7P57@Z?*XGw@2gkmJ|6;}-8 zJotgO$={iD-#~7~M$uGx3Gq_sBz;VUghtd9lJ(}U zHW3CA6VW#l3cT}V z`A`S7+-%Fey|5ny!SxsG8crbx>1)|>5XP?}Nj%JeBd4hjzlP}?Sc`U>BEe!Opk;YS zbeR|;g*zlJqP|}_DOEQdUh%K#;fw1T)+ z(h?1X%NcD;W#W0yI@!-@*`k;1+aw6U^+XA%LmzZ|3My4f%3X$2nB^5z&`>D!0&2^D zQ&zQmwGBA$GrhSnExrv5aNlIwB&$x8F%9c8fO6|qU{L8TMyhVZ;;d0NEa}n}E-5eY zrG!xMil1rrE10p8U%6cc-pmhG4&H+ z`LmjUQ0Wz^Nkebwy%OW>ih|kmf?DG`vnFGN=lz98u!jO6dNPgD{$to@md*jaPuf_E zTrRu-q1jqFg%P>nk@41HQJXOjy2;#@mzGL@{w-GG3ErgN)H>C2u?s~`SY}k*n@9GK z&UBF36bC(uc?R&iil4S9Zd zTrLOUA3Eikh2bhIwd2xC7UnAlqjfJgW*aj;6HU1dEjh`UbW=^aE?Q78e=s|CngN+A z@(lasv*M;InpN~4x+>)PIn&hy4$2Sb+aT)1+!iR zH!Z=Lh4fla55zCC6w7}Li=f-v98o^pL`>MYZsj797g@gRf&;;8*~WAG50d>r%sKgS za+#t@I@7&)+lg*LnryLzF6%ar*ZM&?u-ZI0AU622rdkx^lPklT^|A8za|?cijPhQ= zSGcvbL4aJvSVc!w%@jYTG-nerB&u$4EDXm#vJ|&mswInRQx;QG75{^pe6foqVJGaYBCN;TH)|IN{!7iz8qAVWlXenh1`{5Wk3{kFhZKo{d4uoVg3x4>(df zx5O~fFNaYSz#Q4wlv6pWGU9<;saak&8;*CH&7+<@G0d-`lM7U+o1Kznl|MXrqS9u&Irz#;kQH!n3-ske(VS0U%uc-xR7$C5ZfPpMuRG>pv+rzPKA~e*|q~P7&V1H_qBt8^qSKpdfS%ym! z8dP3dM4%vV3B0V40tjMNX4w=nuY#zZ$QscrHD04v?ZZ6-wRKm>r#fkOksU$v=H`OA zt)7%&O;Q5MYINN)D_yAMPv&b~GF@xBi1^9C=ZrU@~YA zR;{f+msRfAsw@TN5Han+`C9G%UYx@mq}5~hO}DsPw?iy z^Q_1a`@lT!C+QpEphOu@JVyYj_5gN$CCyq(^Fps(vql`-GF%+DS8x3GYMpbFAlE1} z2)oJ$FT6SFA9E?qk6HJZRAEs%uZkVwvua|LFjavIR{Tx zWAE2Y=~L@qw+N+W_Tucn+|?EJU5(+%m8Q|=;*}!%@8JhAKvam{w73WLLd}42Lvf z*n_5qx577L92|fVVKw;s98r6r47hJwFUTJ&GFd<&5$=r zyK>pe4#5V%JOS3pK%?_&mwz36iV2=tbFK6T! zoikvmu4H}8fSdN+*W1!S<~%x|9*AAASQ4UGUgN8jt)`Yn0X(T4K?wZM zzWg(dBETUCXs|R3>rl0SHE&3-jw`eC=*Uej!`V~~XBFnfY)0nVA38^8k&O0aRX=iR zUC}41B`*HG6pl}&b5!94G-`Wx$`>BxsLk_ooF6`T8JSB=-V0N_)G@-`xc*#i`s~@| z_(=FN$P$3HT=AnU=kAh5AEPVpaSiG{763y{r2X{_7Zwt=I$zHwEmkWo?BKv(Nd+O=G{ z&u(@FGxFC4JsNRbE>^pmR=$AyJe?pL!=S?j(fidbX_WI(N2l)ER^0-5M4|NGlr0&) zmKRltOKJJ4mAJD3)xzr$+5%5^QF~%GW?B+%kk>r`Q=4y-T2ajvyqpxMg*hyk>wTfnGx;<)OhMaMjM) zQT#$C0-vf~zcp}bzxsHQ;`qG7{+S4GRdl)b9P`FY2F>3DEz1FI14!|BEz=wfcaBziyBuV6!4J>ozB|M#c8zE{z;)l+Fh-Um6WAY=`FV~Y|8 z*8y&0Hm~iuEoW9IFVN4fsPo}&3zllt?c{a_~O3a3vGrR%>RljIlGbs~M5`SK* z82ME$_1fHTFl{{Z%T=6p+i=6Cln&Us&X0?&MnAnSyH2;&@tlR4 zY3uoBCws9(1p<)P2sc*FfGMODyTj5AGd2hGf-(@a&~at_x;GgMQPv|mclf8YEzIko z5uJ8+4WiYNoZBp2`B`aYyE}&K8;q;{P&+gzVhX)mYYtuqXqh(7)bkgN}DZL#tx9C>Hq);0m%HH#dZwY7!N`i8as>K&fHbzx1t(jCqX*IFyLNf%x@7>^M5N^H?BE^nPDY3`r!srG~mBCtq*U^-mFl^UlN};Nj*_6%BT$%~kD{U{Ox%S8N zw8$&mYs4$Pr)zgoRqAx=Y&1J@Hc>PPl8;;KfDy1fmSECNrK8aM=Xn-e>|#IG8nLaI zoy*16eD<@7(#T2w#uH}UmLNDl!6rrSY;os=Ln!D(uaiOp>UBWQl*{JS+U>tTnyi7 zw)gD`*dli*n{Z9JX_8TbOIIe2^yjv=TQwl-U04^B(ew;YbHs|H78#1{A z3|yJPj-kRHg+mkst7DD-TCsoZ92m=x1+Xb)_M6n<={~OGiGF6b=~+BxI;CpQM8X?! z1?V08P7j|vs<-)i_T6$=LQj=SepoplVG$u~T;oY{VP=L*>6AdnFk@p~?DWk07 ztSFpACm2<;{FskJ+fBSckymcjqG3l`@CjQ=M6qNRmU=ls=+$UW z>sf9P;)Dfp*AtFq9+&f>G1>>a`syd2at73-K>oPXzE9{AfQ2?yP9i%`zs4UIOn5_P zCUqroj3pI^ZG&q0r?N~IJ1g)b)2ET&&oBKD4iaj~70B6q632<@ikVhJlV;9hT`)i` zO#B3he}k1Wyd-3oFFdszni6mjq74}9tvF|WEvyZyPg7CF6zP|2RclpgWla`EDB(Cc z!?MFquJLbF@4HDoxZQi*V2xU0kP)6)l-)x7?b3pvY~)ts%E=^ z(_O7zyxwxv!P;G|7h;{J&h};-$dEnZnbZi~wcS;5O@P2sW0cDMdUZDjx6dl9p?7J zSzfTYvgA*Dc!J4)_r7Jz`atsX!mH;e&93IlW)+x+=-VC|kSe9%+xonRZ6n5`mEz}1 z?}L@WAvSxsqlA^ghG$WGKnx@${ahP)*r$ieJ0d~*q}v{jwTw@Hu>x!r3iok7yeRyBbP48^qUBuMyr$PMLt&d5K zmnDx6N9TKn`+)${PL6)bF2uF064mYwC_$XQ4$Kv-XHSCI*uTnPl75Fpz}!GD9+?+@ zXnV&D#+3u}n7Dbn7{Xxk1ATL2U4p|ZM6NW7U7_{zm=|l?VdcQE&6|_;cWa~*YJu5Z z^NhTLgw*HqwFgMfwsb~lHZuq3+&FD&dHI{ihu#1DC>U$?&-scB;+;wV!rkgYo^@{Z zJHPYfc*gwF2KIB&-bsV)@tSRgI;-nLjuDeCL#ewl0Kim`ZM`2HFH9v{^~{U66}81J z7gI|3=HTmm<~G+ee-KR) zvFiMGgKZ?5?bhOCJM7n#~?sR+yrJd?*jjqlBw5-Y9lq3@@{6@!} zGWN^>75c*Y-feCX1M0+Es-bHbS~2FchbI$vIN6bsvLX}7FU}8n(vLDQp(%}np^}e| z){9z$S{06VAt=M^F0t<5y98Sg!33MJt>*Es;=Nnm8BMu}9EyFEM;3%xdToE=LR{l$ zn!)80`$q9_#m%VM*?_j#cZjd|J*v6IZ=naG1%L(NDOxQePO!@y&oVNg_C{V;1X>Zr zH9;J`VaH6=8PpSCh9-Al0Cz#|%S-(ON6z*KwDk|@T|)8%sLlFp7Zf7;fw{V<=gMD5 znD__W$=Vz;@@UYg5>70c)e8-aug<7=;!mV(vAELcw8P7l zIrMT?>-IZ7OfPYdi;B4&^@E6eXSV5~fCxDEas&6+TYCs^X+=6_-kdtq`ma-T02+&C zh9M2L+7GK;CzxPpS?EEbAN{Iy@gfN%6u)10WL7OCG|y8PAZ2@kvrFi2r|f)1HiOPE zx;N>tPn%7MF^ec5Zl;Byj|3}K26-=rx`SCLjhNC>JRGO_P9RT@PJfZ7gPh%FZBYr_!0`?-ylTl9$!WL;gDpwUC=)9q$+1 zI{qlB>NG9tHS$41NfJMw>XyDQ3my&A4AmtneBsKCF0_@I$)m! zDLLPd50I*Qy}<2nRgHok(E=0gwKJ{|Fy`SJ@YoCQEwafWCrI1PmvVy9}Jd!qUJ@GF#up;Z=(n8`kLgMquyPv!(pVX}GI zD=tlvofs^thhN$h>f;Hqi{dr84xdX%dTS$<5W*1{59 z`E2CMh$afl!N^e1ac1tk2WXdJv!HAH$@8$FA{v^RZfx17Qu@*2TccQp>GFX!${Vqj z?&gy9jZR8G_Sy-%5NIjYW_T==BgA$E*-HZTcU_t`Mz~DX*Rlw0YhXQ33mdrOML69Y z&XR~w7lS<1L|&6=#)PafuB!%Rdb1pe_`rqW*e*GOSLHqRmmy0P30Pupey1HQG#%Wa za3M9%&j&*rggc#KmGb92dNkhy!;;q1?HJ2>0&d4}mh(Y|KL>3EP|?6`6u+z8WOt*7 zX_Q$z7?1Bt;0`~m8y0_OT7eJiyuwPeL^zXvi-fkaLN>!El>nM}QSon~ZGQV6y zSNOQASN^+>SARVIBY$y28>#+h*S?dEJio&fxuKv9KJW7i23Ta$GKsf+g3rn+ zNpY-5Jp1EhMy5M^sO(9KWKFE`f@4}n{3dQ7bm|Cm1O_MrmIvq|Fb_Z0`r zHdYU|P0yULvs@l|4J<@t3@DWB*~Y)Q8juqNX+;EqHEqwJGrxHe@$aO9q6tbel+W}g ztYL%N(Sv*p|2(%%(S>p>k>KL3_RpUYt(Vwx8C#@KS4HN>{ARmF&X1I;eDwUNTmY#E zEU3Ii%Ch4om%%&8X-QJv97Wlu!}!eoAMdaK7?eiYa0&KQ6rYu z89hAy=|V*P*AHA5l#Vnp|%}mm1x2S?gLoBXRVs}JwoMwH{OM3JjWMZPT(D4c*-anr+Dmj*F zJ=R=3@_r3OMJhTI@P=icu0T2VEE~3f*d^|g%XSQB?zSbm-xI2`ZSvC-E1KuGdLb}^1W>d(h2V4 zkw<={Nn*Xx$J_)jEad9@O*nt$ArW>4k}zrrVoY7aoq%Q0=30rkg#;}?gw9&=MP57A z=aZmNl;FzvN|~RL>QhN-3I*B=1CDC7ig8fV&ppJjVc_KCW~D4R5rNrAOU1(tU;e;x z$IX~uUK4}pFVzRnyk#v3Bl(g}_6+$#vMQ+6Th)22D7Q|H6xu(hZ;&8P$N?{%T4~iV z*fs~XbpKK!8TITBV>=F88uBDV=3}vjd$!aI^wu%gvwo`ecWg3LHpr``RaQt#|4N^} zpHFuAXRbxmMs0{jB*31X#{j40$T3FNF!g%gM^Yc)zBL+?a%L@M&5i<&QoU;pnN$do zF!3oZu~<*cxQ%j|SNe%VTjBT1%;y(fD)lKC&eZ9ubv#g=D{4e#A*7mQs#q09hc2HZ z_(y^=Sxi)@pFC%OJH~oJe%Zl$Pakx<&xajXhp~&bGLNWFw(;oLw^U;S!@sgZ_u$|E z7ggT?EK00wd$!NEZQHibwr$(CZQHhO+qP|6Z{K(S|5bmcW@;u?>2#8r?o^Uq%fL=f zZ+6x!HmmYpbWpCES2dVoh7K!}h8fd8v%oJgAZa;B-mHmP&q58_JW}q8hQ7Qq9@-^w zglyg1-s-JT(jo$uYA6H*F&8CG-M~m{{{wZq4B2TswK(Xa11pyHxTx@ww0KC>Ysy>`x|Pa_Ahz#8;)- zJf1;O_$ToydB4I@k-;yB2lD4?ATx zEg=zwEAVp%hN(``3BYp^c9$7YGaAam<KvP?K#yv z%5c1Hm@+NIBRA)fwMRhL=*boAe zm`^p}x@z^Q5Kk^v)D{KO)7r*E*`bMGQjIGBKrGJ!b!pmFtmg>9y$1g{#^a=!MDC-j zArVRj*t-dqx}sg?@j($gG>-*%)MDWv8@%s!Hr7CAkd*2%P8jC~*qqU}-fB$$A=}2u zbNyhn-qc?iCRl9cYy?iYXvI7H%F2Bt1Hh=KV$Ut$sLrgIOv8+n8A(Kmn(H#|1X$n` z(s8D5AIybsGd_||@EDt7gy_M?HhK&ftldv!w;z2x!b+fF?xW7LssxPi@A79;{Ke?{ z44VB#L#~0)c5)3_dD0ka#e&+s&!pR|0ZC~Hq=^by^w6imXx!URbVmNC04i`o0YAJB zJv@AsaMEQ37zH$ zG$Ldiy|c=Z(q|Nz6vahNC6*)WMYH?SHFSunO$+c>)E#05iWu`quQDp$IwDYeE)!_X zTx}QYKt5%F4q zXEXulFE|GeMgGTVIJI~u4U?c3B?V=|dEI3?!}9>>?x^~48-)oo5A6=%;bH}K()AOp zb|1KNi#xB)j)Jvv9g{qT<`q70DxL$0po--*wPSFoBHMA#jAcbRBZ!Q;u+q5d%dKSn zPVheQZ;ayS1PWBnc$iU5CXKVKf{#}F!wJ>Avv>5iyK0@|`2DD8$cj3C0pjytl{&TBu3_TwZQRiECG3o*NoNf zcSkaJ*zm=zql6ZAy{b0pBq7V$=M$OOmUHmJCjGJl?b|t~?L)%>6hcm#+`q8k(&v(L zbj3R*62Y_OIN0Z96~69rLJdOqgplM9;*qwpfVb<1*lzSQHG~{s0_l4k6Yg?XrBn1Y zpl}$75&S4?Aj=cPv~Fl14YsG@g zcxKS{N|~~&iXB#1JV9|>5$!PJ5;dp<3zxP0Td_h^PzL%*4ROD_ohK=Llo4 zt)C@|H=)6c>geGL>2G0Cyw(OQHTz4dqbh`fR6eikBiZyAPe(=ldI<_D2Da*~G9TJ; zdhXa%d8vikJ0TCv7^?k_eUP#?MYgjgX5_RFa4Z>?PhY9f+qo+y5IqEuEW$)DnGSAi zn$pOaOmJE({|I{X9NRliw$`}UOK{w9dCFEhuvZ-j1nv~v2I3<$%}iMQ1H=e%GB++X zQ(OUFL3HA;93k6J+>rLvkaavshkXKK24LA`F~~%x-B=2#e?g&3-~FTZsRcfImVt;Jky;y*Z}iZd2GddxwL<0=b+=#z2D-sU=8 zx7}_EeA%K0Mv)BXGb6bJlGj?K6o!wJjn1efQrczZ-yf3!t%Y34m5r1!urVqb5QX*) zPTGC1<^pHgu5$}^<3;&#T@jmr#T!?HkGusy!I0t$-)SX40y5nf# z2(`eKXhx(W<;uw4nxAC{sVTNi@{o93{a9LoET`xM&x5LUawR2X`lMGd?NvN>lfTlj z5gLc&NwpV+rpv19`SG)&3!Bw63^?FRfmel?6mKH1o$Yy_uP*bEX$YItUjeP0_>ryO zCJ~bS1f^6pk&K{2;HJb$KIohDqwZ>uD$2(NWd`w@4QF;MRBjyz9ym=+hecLRye1%3 z1mrqt@LfYgr@{FCSjG2KkG zVhnHd5vS_*?g~B2#!A%PpQ>c;c{PqGXQAwu@ygA$7-)}^D5Qx{BKD)Xetq{(-@>o5 zvLj)#;7ZjJv)4la=+U0H?MR@37zd@Q8y1M*B|ol9Cvs7?N6@$ecROx>pMK6AwbrM< z=qp?yzD@#;MSm*(7LeU$x^#xT92Wd$8MST++o~V8MipP1(v@a|sX;VxAZ=6f@g>!829&IdP1Z~2CFA(B_0ioA}G<= zNJIJEt33YG>l>?JmfA#^bI{yRemn|wmG%y!%75m}CaWImfe7s-%$&O3yC z!LHAD$}o&!Mvd9z2v2GZtU)k7A8}5QrpjKf-iDU;aS#!uK`36Z*)*4Hq%z;mnoDqJ zBRnZL+S>4@x`n4Qk4LK<-dVvfP5JPnKmFqnf1$}Iu+jrvnbWR;w?EsYm(nNtzEjMW0BC&SGVKxti`A}402_za{By?My0f658 z1yf<<>KV9u$FMhN+8+@pV*#`nCilTv>gAjsrbRY2OjD(063Ys`^`xm z;??KuI-0bT(K~Hap>MG7P4iwm6HLc+-L$4y-J#Znyv1uPsAWr}hZnd{ zOW2(zKZt6br*Zq1AC5eu# zOh~A%r-`byKT0B`y@toST3FFexd-8`Iy}XFgw|Tw=3;yjaaE}`B-|Q0B-=;<$=DBT zc@E?3umk)i&6jYc$gI6A#;J^7Z2xPklh~Ut*mRSk^<3HAPT?pu_bZrQ$4=N7w>caO zEQ(@6hd_4lnzH_Dbh2aQt%HJF%xo3shW=El|Iwk=S6_OJB7P-&w#)apjjEXWTo^1` z8HLp^AsC4W4i>uZ9Kln+R};W*2rsu=&r0S?^B@RJk(Q$RFNJs+unuW6qem@ub$I!7 zAQfRB=#Rxw(yU`rS)h2xUj4v{wu4Kej|;`>NVrA8@Knbc#6t)9cx}MrL2fA-ueq$Z z24~Pp$uI9%+`T`Uinb*Cji;<_6 zVY_^3*#skrM53NB^>56ZKoWUZisH$cvYj1z1$9M$cOP<0%<3eH>mrxOs&cx*1AtR2 ze7P*&u*u$uXlAv;xNwh1-cK*)O#e2o1A2**B#2NaUI2L!_pRjmy4Qa7GyJs zwr!`R>o;uq0|%u(1bSQPvS(>0#|*7vg@QRxMtlbB?tHh8>UuoYz3)81^fBeUc8S$e+V6(Npt_IspD^BTb!#OjSB?X#UfHeOGtZ8znJ>dVP0wmpTp&unm20!;!MM=0W~$E z;>OzMcj_TId~)AWofGnzD4hwhnpKN?I zq{rCP2M5WY%#G$h!r(v1PLDfP1u_M1H!*WyD7@S#R}uQ;IqTy>ybib=tHXV~05c^u zZ#Ok=K2s$;@|fY?$J(tA+vhSm5#H{QEj&R#1Xg70FDh@=58phIcbr%^BN>#B$9FF( zFW6z;?`YAy(gWDT{5x^iBAt&$IU28>m*{FATQrdltr!nJ&l_w#kNGZKcMXqS@hVYX z-Q;iME&Cp|Gtf$1go#;};@yQ1CTnm9Y|%1Q^HVHPccUkP^n=$k1882_`LRu+XbUk< zo%hop7H0tiIVm!wJ@!|yFW^DfvnDi0Yu@h9(_Vs)96UrPFO1Q*>}`uYZ<$!ta4@{g zUMEkj?|5D9%0HRqvvM!I5jPr2{GK*SNqd}QKhSQZ2wzwhOe3Ppm6A4t$)=FxZ)MragJ=_tsD#1NIaV}SPQaVap zW`Mx!X^YP4x#Ek`oElANinR+tBJ0wAML_C~27P)*6n${^Gd6<>B?`ToD>@4*1J zN^S{$m42^^s%o^gJY_v_H8LQFLwH2L|B~sEpcBud%kzCd5b}Nfk^RwilI?K)wzV_m zd!wiZ)v0#cmjLa`KruuiEB67zr|_d(*SptoSe-NLnfIJEC1SqgEi#l|>ngc}McC{N z{@#9K4In?aSE3jq<+tu(ZMU*BmYIalela!3#X87#5jCjBZZ|z%G|5%_uY+?~jm5EH zLr7AoMND_Ix|f@YM8Q%Lao>PpH~`+aa7@T8FZG}|bNS?VVFr)u_ZzEXR8N64ov>pA zMa3iCXy0xyWw)>S5~^x%1FjXI}QKjGUb&FwKkN@^lWCLe(gMIBlz z&zPN*Pv}|1#xU6EImu*IH2=DcFh~g&w;JllFP&@GlXU#8C`~hkOgueSBrO-u+QuZ4cql_Ng-RThAOR^XHg`Br zAje>2e}*K-;ADTMC}%%$IIm$U&$CQ&7s|Lmn0_L@5VwB*k8Zk4H9GYt8Kf!)+zp2* zjg!lVIfTn&anJ)$^r~=IZpJV67=25+)bM8|kFZD(bo{Yjn^kI3G2wG@LZc9^UKq~|<@WX?Qnm$( z5feA{kidZvF-mgx#?EJ)Dbsqr9>w>(D2t5XAIZ-&*#|Iqh77@}mff;{iR5h*+0{nESgc%3TTudS4*d4R+%%Sn1 zN)lON{}Ik7%xlBZq}z!!FMWei0#-vtVj|($$X@G&6AN>owG;Y>jPpKB31ut=ky>Gc z4s~3PF6ghOj{!vjezkY|*rl-7hVG&SOD^MZqO|*b1a(Iw1O&K7Bx#rA$#NEaT-p`J zTMK6>!(+%$5R(=GIj!nHE7~?Ca{2NF()QH6U-4{niFX8Emvglgus}`n08}bKsLH*t zB`P$NVRY~1lw8KsVSIUBV?TdiS7pql`5|KrNS<6SJvznZSK?-z_EQl-$;iv$q5U{~ z`#J}cV?#ex`{T#+R3QkxLXr>ns}J$am648cdy;RgY~7 zmoK!pEkU*{@zGe?q;krq=)IS^H!UQ1nYZDjO3hHPV;RD(IKK6QzhR%I{#!VVwad`^ zifz?BF*n?;nsYm;z<9B-?OK&p1fe4h_lBfF-}yjLqEzVWLV$SJ zxYlz_>(R7m4K~S@ToVo|X|lw3MW=ohfe2@tb4tHlaWQPpu%9nDfgcDzdIU+-jtegk z+c1|AoYMAcOEMy2=2sn6T~fgME|cNS2ADzf!xpq zD7PE^FBn&)h8aUvm9;uzfz&s$aZWUI-=Rw+{aX*sfw}YJv6(9B@FxxP9WSXO@z>bw zk24R(5Tm+D#P%ui;l@KLPRftkz=jBCuFVbxhHxH*;RS0nYX%#(3z%R)Oc+iweTyY6 z251LO__mN#-U9yRK$+O{D^l}F-r^9}>2)SV{Mb?YIbsG6A`E%BftYg2bT8N}8zz(Dwa*E%yrx~S?QGvPJ{`!1)Hmxsq4E63kzQ6(@J2y6EW+Wj=qTrB z(TPzVk+6uBDO=5Vth{KCdy0rC;9737m5{8`p8Uw1+%6A0u3*+8xgD55oM4jK$hdm< z=>P6dGJ!~7!y@q7jRZWUtOJmF%-AI$wB3CAu05)sq*Sd{q;8g_YId09zWIYDUNsQJ zYLz{Fq>S1=T+Co{^>|FfX7Bh#tZ?>dp(-4^+zc(gdA-m7jC`VWNlo2|Y^SjGRBfrw zTY=kg*uD@6crD;yC1VHlhqH;9!2#(j69GSl|FpyKE`%LMkd92G<&ul0l6-G^vYR- zaZ#ip-P?~|@!8fvallt5^S?3%&;4RWbh%})ONZz6M12{c{{_5IKM50VoFZ8mk-J{H zd97M&T-5B7AeG^&Tf9OBd%_&n&)ffOtKmj12ePz%&>+H$Y~>aHKzC~lAZ?2(ChU=u zGC1pX^z-skfNALfX6)Z|8Z1i}_LxPp$J1^biHutBWi%*TK(%!*lgyJN@xyuZ3c|Ok zRWEW6zsgWpR2jMmQPDx3tKCH7T(wjk_31KS7A0F{tP`x3O*ko1mGgYZL*9P~QE&fI zG45XhS9o!gOz?6UBN`0?s9)USiFL6E*1)nNPb;i>6~d_cV2F*nlyW`IN%t=#f$@lQ z8X8plN^FWlXNGN~gcmLrTiy^idaALlMjk@~d;Zv&h{BBzQkIA8h%?-wzA#wJ86liy zEiQG8SO2UQvv-H`Y^Vx*<$xP#6kQPCRvYkZ0`&>lu#Dt~B9{|6jse0%l>ECUjNYFh zNL-$rj^r&m`JBQAuK%{-qYXlWr@1do;3HTe^Hr3_MJruML%4y$wi8ISJ7><1O;q!E zKH+1<5>|j#n*!>2pg*h|F{rDB5kId9OxKUF`^G>y;9m(FN&FWwP9sRu(A~(GlCtp5 z0J%5R!9F19*n;6@mNZE^n#YELA4;0vFA62hMqwMa)bs+JV!UkhlIZ>Xdap2(DWF@X zdnI=!wVQmg7xs5w@3^pW&t#)oXg6)e=2NJ{y+HYb@*p>o9KvJuH(y+#jkzU4%OHte z0ex8fseAdt;MA-qwPraHDhgzS54BWGx^|90QFt?2U%o*-+8GRT#bAW0eVEKBpoTzlQ&d*_S*Q_h_eu&0cW z9=6v5mT{+X<<0rPv(5Qm?Nnx-brTzJP<}f;pSNu$%f+iHEhOQDUJJ;(`EWA^FIIxs zdwiwK6(q0BKP3W3<+CoSC9MSYn}IJ8bWpvd`4Q-ae$Cqaq#+ez{((pxe+aUF$VI7C zxcu4E!%w-ybEE(%Xei&Z9Rp+xHQuv$4T{Nt^tHK6>Lfpq*@BW85T0r}2R-8uHCjXk zmyrn`N{$9m+D1W^Ix(p2xzkGF8Hvg@nORUWM3XI+DpGRc(}X#t)Ylj$u9hGTljSO8 zjFsG+LdMf`RD`#k_1AZLGC~h(QP0{$Z;Bs%RNG3&<-gyo{`Th-)-O9?jj=P0U%K4c zLlcrOH@|5$>MKD$WTN()@7Ib_i_}T-@;yP^9J+5a6>Pr(r^gy4scn#3SR<&7PNt;k z6<3NLV;DlIg8v9Gm4qsBdp6Tar^P$i6snmCfUrljF=f0*hv-*tj5U5zG!j(xi9;em zGOP3$l+Rx_nrKZ(fI?ofvfF{Zix-N90L}Ll%nL3Q6)}7L$4U{d%`=QpSDjg!jp1pi zGpGW~JYM8&?5H1kZ;^?#c|Vd`$`haVTqOrSLE#Txq;WZ{skS$k^cfF>a#iZai>uGQ zlj{AI5Y(rrNgPg<>B1jMwk2IdfJC$mD`yKTEt2^GuYpQHNNMPLZ^@e}MJ_~9BbpED z)ZX^Zk7Y=VW{a$Mg9{#8hN&OI%StNUIAZ=*wN?f4)U$R!g^!{M%PkLCy(RAb4BEqNy7f>BqrTe|P|kmyhIlu-u8o1^VfbWmw&W$5;%FY|$|N^|+iWa4w?&amHBoK`EW2kdzu( z#78SK94whwlcd&n&Pm+}n~?c^feDRlu)2djPYES4zOq+6Xq+oBZ389PXj%Fxh z0BmPEQt$N}^sVOYq-dUL2A_VQ+^t_fSn9zs0v$cQL}b#|G+UdVP~+h-44pmwBsDdz z!p)I>pv+DBE`9#E5_Jhi4-wKzeG5e{t7^##X^DM3)BAm_yxl3ELuE6rWT`3C+@#2K z6z-a<$_-t4qboZ~ZM|AOu#w%*zR2x)b3^hdu3Pz`aeHD4uWiA`%j>X}EjMl&M&a-w%Q%Mm!k6WwGj-vhB^ue` zogil?fN76Cr%C1^Q$+pn;g|8HZMRc3S0O7Qam&y3@S%hZZGV@(x-n{?3(NY*mNn#q z-BYy5LDe}b<vG=#H*EhGr6-7Qy?D`#_eML_C2)2YkH^KRg7FR+z#!m$}rwzT4Wx=Q@Rx9=%j z2N}|vXGf7vqg~A3z`=4#q-FSL%l&Eic%&yeQ&oXOhKSgYoBBts@k|lp%kd z62@q|;hH3{X@s+(7LtRb*t%ToGVDAGqnSZ~%18jmUE-0nZlkmCIp_lllkcI--{lSJqA7qLz2s0rPL7WhcCW(&2l7b>+Pk#+U zMGIOM+x}N7e9t0a@f#e=5(d2_G|g|dgj1(>AD3QP6(f@i4#~p{pa24{TnmfHe1|3G z-+tAJFqsN_+&VHGFhQ4L4;_k=TT)yH@);-^ldd47ztF1m&oN-ZH)o$Ix0nrjvxdzI z+aMfHLIzYpss2;TV7y_v(wdNnp9`EPY`fh%^z!4m371#7el>_HJ- z;ub@sgcOq2zZ$fLeNz^IsR=bLg8FvCX1Er23_snKSKS@pUIpzuw{%CFlp)1kv-H+n zxiLFmb40Ls!>qsg|M*p1mn~rWDAg=;pKvZQXUdWX^rvB_ERZ3WA&)gEq&LF=*F|ji zji`s3EpW%+AgiHvno*-@i-%F6h#Ds&1Rsn8uI9Qe+tP?PMC=DMxfSafU;Bak;%joL zU-w`AE7nEqn`#cX99mcg(sDDwu4HCN-zQdm@T`<5GfErYZm0&568K3sW{JbnH$bPZ0DH47IOuJ%o!~Q$TuO!OMw>}{tWxXkmwylM3-Z)vBhFX`P0jlE`V75- zrLj|miKP*sFs4@9Az|4fn*G=ZyHhjm!?msW{p`LLt^t}C+m|_+Lff1B#mW{PpXeo} zP5X;`hdE=J>1fUEBsri8&M#64@&pZxakI0eub3=fn=&mDRgUD1fZ`1VF&KbvbO@^% znpOKRDHWT6SX@t}w3S&#L~R_rNt0HPt2S9zQ_pkr%RiS4T>E+Sybc~NvudxGKIWa8 zbYFn0ZI#(D)Z@O0<`(Cu4$~d4-X%9o;b|tF(hKW;iGTal_?U;scqG?4WGX<;VTVK+ z_ytls@pCt2n>870CdVaGN#DmU6N5#a=u^)h9%N1DjqYG;l5(SQHu=zm0Qt5c2)FZs z!*}XHA4@X$V>fH3NoLw#eomn?Yo!s^x9VkxXQ%L_@F6IVNQzNtGh z=KMY`G!TM=5Le+_;r>RDuw5JZ0FfE()omSl+nf(!8V zq!>ZOq}^!*Ma?|G*{jlG9Y8qJd3{SfbI3jujd!xFP`(LZj?%ZDx4bF#+|4)pP+;Cb zGnsuJR-VFPavuaW+e*cIIfWJuJ*GW1+-F;O)v@YkAoRUN^IF^*4bcZ{Ef2?VrHY7a zQtY26V;zva7v;JuuG2LPa2DTRmhkrW-dzrqm~0Zha2*T^K3lzUUv6?8!r`)94Hai0 zj{85mg!Y)X%o6M%f+;rSIj=avu-F4itZ&Ndvhmo&IDxT-FI2_B8VQ4SA2<+@b@2ywG(JiWe+8o;}){`@VG zyjwzMCqVK?g$fwTxHPkkTk1rn?G0dV8;V1|LBPK2ggaW2spQ|j$FyTp_%Y2EW=Zr5 zK8-{S)Vw6sI*ReR_uIbfj+lP8tdq&aH_>>AOJ{#ln=LCMwb8YMv(Twjthvjy4LOOs z$=Rf~s60+Cjx={R$nX-89Fkc)&8@CDc1xT=z895;aqBoG>z7XitVmp76Gq)MpxZ$U zqF`X{oDxo+2I@;YYB3Cpt4 zAUrd#lU68%cO*@1H6W|j-lb$CX+y*obInrjtSLs@mAgZ}d77{ZhG?gtr#Kn(isdu* zzVin-*5DZL^1cW`EDZ?>oxvq5+1q^~-zAH*6i0%jWZ}Sih>L|m^nO3myp8xacW*m%%{zW zzr=?MdQIE@We|2agJ!FXGBnLk@=nARc+~(h_U2T+rnPeoJBn*bC2Hv(3tSsavvUs# zLalYg!AiUz&C5dyKb)jY6a_p9yrZ zP+)|AKr3&ndtF18o(mp?AzI#14H!In7FVs9ZmD$zxPqDF{^JoqdtNz%1W!MURcg1= zW1UXg;k-UZ-$|e;=Vwn(Qs{8mHh5@Jd7xozq&T$FXJ*`VKn7{y_qr9a_YlEJ*Zo&) z8H{Y(a5}7IBN8Zdax-E7H_#pB;+3C!a*W)&(iq}au+u;oU^Dp*1lvWF1f+vUx%w5! z^8Gk(6)EjmjQq1{+3;1W$29&HW=Kbs&=q#8v*+7M78EG@$RIM{xSNl+c*%t={F^&| zMby)pdDUw4AwFo>E!2~o9l4>bWs6JLFhmgOC?3?Frbmt*co1UEXO4*k)jybRKI}ya z)%1dBr6R!?pivah77#v1{7Ht@fp z!ZzJ6bt3H+3cz3f;x6~EXOGK+~+eHl;6SNL4GF3WSsEmE@)71hyZj9_^`Lopl<~CKC zAOfrzPI0#dzsa&BaVJ+Tjf_eQ{OE91tS-jtpFR{jV$QVCK{}$ikJk}Wha1C^FI(x(= zq6_v4A*%VrzlIav6-bG4T$tGt9>x;V5L!rvsf+oK64o1Frd?W~n?oXOGkcs#zTCRL z2Uyi4@fR=;VG^x^8%?$J8fkddQ&6iMVCvpDIbvWN?bIHa$Fp0xwOO`*W{I~RJNlM*=XhB(i1 zrQ4NALz2^FzGdfFQoAjyIq2|}odBm2f%J78=TuN(A8r}0m9f`aAN^d-DA!>wdIU#Y zNTpm5deTFA!E$D=0bWM@vTv9(<5 zxnuZ^6ooDP`ghVycfL|GW{eeD?`D!@SCXWgmq@Ift%Apg$}ri?AdYT^Kn#rici4o9 zQ))k9BJ3SVd3c0vM9}miV*{MPV*&(FIohtAi%j|7n$D?Wj)G>MUx9@9;veYKeWslW zX$-sIBvepP$pJ;e;yG`|6kd`;A8QPMjp(H;Iu=@3sbUSKcO>;cT;m-`7?gL5IbN#$ z*&CjDd;iwqav_cbyBR$6sA6Jz?s8+eK|cfs)vbjbM{jawD4tmQ(qFrPy?9*oa+;ij z(V&;dkdYh3z%B{YsOi+3R^ym>q0_6K$oWWzW} z)GbgAPG4hHc6_-G70)e<@R-&IX=B!dJ#%y=+;eAYJKHThfAbTST(02e6Ddg$_efgGu`A7XwDI=s156z0l^60q zRV@fwu4cTfsC_Nym_JA{E~$;J-g&K^tMarXqNIIc+)0(83i?no8DPU#BOOgL1 zlCQBO_7DxQXJ$yWl^BL6DBP1B5fz2r_e1OuYfO=<=rHuLsM8leLB-!#BkEAxYv|;W zlfkUGdg@HG(&8?-XE%7NkZ;cHEeWA5aZp=Gg^1^G8entSO5%3H_`v~7=kxfYNi2h*i*FlAxUGP`geJNG(Rfjg-W+cB zd!LUwa$X~E3zz>Legl7ql}mTZyUS+=@zg8DOMX_o|M>xk4`yr#@ItBizFukAT{4cx z`)PbF71V_4W`YrH+j0^LBrxF-qU^LDo`>2h7gv|P?K*dguML#E&pfKSy={NuHH!BV ze}!!PI*}w_q}FWIr_dI&ZVSChlF^mArAY}J^gWju2XK4J8K*ei$B(Swh+6X0lLvR3*s)|usv+2n+q@Od`H`}`M3%s1eZXV?~}YT?R&#Ap#(NmElq_)rbmF_<8aIBJ3Zfj z;8ud?ln$QU`Uk=kkCkbB(@8!p5&sf~Z>JDM5s=`T4&qYQE^x~$bmacSl#LVr8?=XZ z$5_HuhvyGB510tAZ6gdWso-Dnr^Xj9{aH!9o*aSq4gGM+MNcR@%(=D*`%jOXa9OdR zZ6jR>E1RDqAuo#a7I0qTuo|0R2&hoqLt!lX4U?U9gJv!(H~C{DDIE(p<;0wE2(yfV zlr!Nw@=qtL+#daQ8tV(kCNoS&aSx6zFe@&bo%R_^a8>_u?>BsjhH2yu^7qyXpb%OX zNBN);P1M0Z(@Mv{I`u^_U@<45#^(fI`iH_xe@7Zx86`rNH>K-HH8*jZ>XX#j$@)zP z;61nbk$_`3fnO56RX1wEW=0{`kDpx2QHYT@dy1qitc%c65*(Z8wDxPgEM~E|=*JL5 zVLJfN_^kw~Vf8SbHYZb+Zs4Ffh1c5mbTwpZvv4t*z3nt!)oY!8UUWAS0XK#%dYk3@ znw?cwo$W1+u$sH~bS?Jrfe~~qkfA+<)`s_VH-u`n=yel(p+yfht@fL72vh`Eku1A@ zxK~k1dYfs`S@@E@RS_0?4=$8zpJ0G8RySwrK#ObAHJqGGF`H#g-F$Bmb*ylK^RT1| zk<;6Vr7tF_)gGD=lJvxigg5xS+K$zT#Y&(?C*Fer&r?BGng!L=j80 zte6g0p91og*;2)p|wfY zTXAET1&Na*ggpPEMq^sUxzGVj1OPCE<@5nFCwSl$pS*J{#ifk^l{__hW2NS;&%Oep z^57n><9J0(E~c8LU&%ych36cuajG18B^P=IL2te@L=8ykFA3g5c&4|@vP}CCx%ZEI zn7x@g0wg);Y__;&BAznevy1YOg90?TuS#+SLmGTG4r&tz)OrDLH@a=M9JqR>DZ)J; zpU1a+OR)hsBf?^;`gdU{Z_om>7TxJliGO86Az?)bJ7R{Y7 z^kD5N#O*SI)K|p8tKW0*qO= z%@YQt1;z491=Pk3AoXLwyVU#pf!0jjD^s;vMd-(x%d81dMZPPRw3Y#(?X}tzkx_FQ zU6%_uV~_8pRs?Ti)BOZE`MV+M&A+CW;hjmDF4&6{qdGPo z36`mM=a19JN|NjFBj56ivUZ$*hYW-@ZrVPE!s$B>GZpd}yn5f*y$$n8H*Nj#2e#Koyr5$cv3x!nlHzcF#q8 zv!9dAXg9My%z2<4tC-*1zG{PNV4b^PX%0G`Q`mXQe{Q2 z1yuMmQET2&j;0JwOQjF$VybGvzC2hfA0dDH5@q3O`*&)0XdJDZL7XTS>ssi&}H%nlymWkv8R~!uR8SY>L}aj7ds^YRce3(>{95(KBu zG9sWdR^bJO9RyJ;=D_atL0v2FkibrcgkVG)wClT?WvV|EIqE8keqBZcRxl&R!WBU%a4`aHPpzCGpQEvH!9MMG*y;yBaX zwye2A@FYwgpgC-@@E#{aA;HN*(B!vN-ZbjW1GF?`NS`Rc;(Rm`2t%K~gV7b!L427(j`=Qu+%*phO`1t74 zRZu3R17_{%P$ioTGzM&($eCLZ(-a^k3H}XQeQlPZR;TeuY;CMQNlccr`*=7Ysb_nO zNQ%pw z4lfD;Wu2Khyn5pr7bJ-dwJ;xIZhN4*k+^Ijhjm$PWUDHL;ZR6c3p9baBLB^U zrlTXY?p_6N#C1@no~W4Xb97OFHa?_P7`LZc$Q5V>&mu}d*da<79N|c3`Fk^5ZU6D8 zwG#KUI$+k-DAU#8q_PAE&(qu#=D@O);tJ%3XpYk=gdY%2|En=6j3MS6N5Ju4-l+y=BaqmEbL`__z%eJ7qM7NuA_(n%)eu50!;&^IWc#hbH9-_nyD0LZV4El*Jt}z% z)IJpISuNkMO2fN`E2qkBqQv;7Nxur}{a!?K5%j2LgSK({EC^R>gKNLo_wiOvZL`t#aq?1)Oo0(h`I?1L zfa1R;yXBrLwTZ@Y$44;5pAtkBwu-iq$HF&26Z|TJfjuTX&gWME+9vAO2?zDt#AK*u zLcfa6qxdE!(#(h2$C2z$mDS=R>61}v75>)~VQ6=Y`gc+M`k-K(1g%1@2vH@P`BBkd z4f7)!nL*eF$Ar`WWbP3}q5USy(##V>;k?o;35P@3$1%8$Cez4+Y^#H8i~q;!Z?_BG z#*Syug5&6qul{-)5R_b=G- zSJZ5Nz;BoSI&s*wdExTj3#DCVvRgoi&g}olq>=xR%->`|%tL~t-63B>IECH|gIlyx zAyjg~P_82aB}(TD+gH4D5L=$E*}SgG!)vl34+zcpbO-v5>x8{!9@w`CUw zeG?%ZKSGkDDG`mI2s_VrIKn+b6Q>Zt30#`}o@>1;`796wFjw6pBmF8+faC#RZ9Q&T@tEKokb?S9DB2tBx*|rFFGGM5bCI9{1Qs^rYv{MJ5u4ikP<)Mgw ziwyj8A-X&x{r_kEzjj)R57~x+;5Q#MS4@=eiSv^ECNBpIG;wBEw95Q}gG{ZFZ$IB~rhL4Y_OSi>0~ zLWVXvisAsT`DR`tg9OLAWkC%i1hVT z3`(I7Q<6xM50lf93bAeZ-v0n*K$*WwsAf=+XZS}WhJWc^?)j7q+%n2tOjq}z|bmgkG6)j4sYtlLyKrg0@c@TqydD?lHQ$e%>YI8KLs5#}!- zkU-ZF-<81!?De{^JWVg}imwV=Wb)le7C0)8EHT%CItvk-h38_r_P6YZ2vtG6;C%ZJ zV_zB5ab%o-7jtc{3-VVm`AqT>^{k~Q3N#?RlEdrsnq*eC8P93e+4gVTPYvPz0(_4l zuKHg3dR>E05@x20er@U_j?6uLV|XRbVm}t6exdxrgHwNIq}up{-Gy}bJ_d~Yo{sbJ zYE{9%o=e1Y7ao@vhoOXMxluXZV%*MHOK6bAAoRYwA;w~qi~co$#1)-}8K@iA z6nK!nQ?Spvi0_A>hiAYWvlI@-#_$8Z|VM;BEpowf8oF1^AbcoSFAQ#_8iELaOV7Btd0UAgrws^-% zi-{R+jXdyQSU0h0f8862H~vCUP!eFdh35BURxy(6(s4)77|uMI<~ky|^qr_Q%3mKn zITJPW2oJjVdkn75vP4e4M?@mePP`C#cCMxWcM;8AS6z88Y;$)9{^0Z6>V_OYJy}uxPsdkC+0Q zP>c|(N|;17u3feuD+|jD_ilgis}^EL8x<_X%s4Ga@2~`s;spGbE=vanGs`5xwPW;2 zIK6&yls<46{DaS^O6lx8F%jUMu^JOVjOhkHAe>9#;)@z}-U(cJ#_ab^hSZ^>@DBAg z#0USHatMB&==GhlK}4Y41>#<-wk*#oPRZ{}jVs#3OdH;(T;iAK5JU9hrr@Fo7M%Hu zTb+|v=ZkO_-ht1m#`NP*ySv|>N&jb!?x*kH{(-AJ{$k@#wj6x)J-^59D5IYy#?Ky~ ze+tj1@gHfZliz2*nNQ6jC5YVT@H~e9sMJO+yFX*E?z!Kd-%b&H_V>#^E?eDqKdR#k z!vRze%j#{Ye%YSCxlcyv{{RXV+4IrOX~f!5;5^zn!M_c!eq#9o{v)5?8{6}bBKxpC zzcc5-9P^&A{R~e;du_vg9?b3RIgnayQHxlod#q(kKq3S^<(P^zixd76e>^J2sqT0Q(PUmpGZ|hI*2ZINFaMKCPnenT;pc$T>jMbv-bR5 zff!meDU9vuL-zcCP|^)*o?bx3lM1zeC{D3wF75-iim@)nFtz9JRWrfo58^+LjpD@5 zeUxw$B`6@#nj}X@OT3$QlXb%(8X%e130lN^LbhT1X#KvOJ?*KWCCjJchRW;X- zP*Nk3Ea$&U~yY2Ze@UO2sS|mk4UMZIpSItuDnlm7DL<>) zrW&shJD|aUTzW|Tnma_jTFs1#$HT5hL3@I2^a>bs1m8F+N`}8GV!D^wX<<`lh-K>Ni4IxA{8EgAlmZh03#B%Z9 zr&o-t5QZpI?Vj!=?&cXzSa(?A3XBtYKFRV-jYO?;!br`*vvLkDORjlL$-{00PLpta z0!wV4J#!-))ov{HE$V0LAHxdX5noKK$qc|lJbApdJz{4^!X5PpPb*XPZf$m7#O|cR)WAkARZ2eth$cTRXX} zhe9`@j5PXVd z2Y^NyM4=TWBR<3IcY>6*>YbD@Est}|mz>R?m)K%+Lf{$W>z2@0A0fE_8OhB^$sPoW z3Z_eJ6ewM-AbSi-Ukx#=28CjWQSonRMuPbSq^j!Zabxz>Bmq%~H8CtiHTFO>X zisr1svlk-Np1H73imKC_)nH#vFqL*uHR#rUk~1iyOXaWRw;D0)-#kiXW2LHL zTb)yep&I^^F~vbppnV1$93YM6(?>BCFnEx3Wd0Y~|-M&xy+Se0H80&a`F9iB>HgYTSDR zYORcW(dywvdsceU9PC1~H*Ym5*BFuMU=P{X_r$35W*dI9&l#x+-n4l}s?A9KP*SQ- z4%ZA{n-|_RuY;X*a5P}(FI2z+a@(?Es~T`W#W2Ej@3AqC@)I;E^E@T%jeH;B>nnU2br+ z)umZFL??UC#^ClCFZ_YQ=f<&@rrK&b17EJXP9~#xC0g=5DSsv{Kkkc5_Q7RP^E3w$ zxRx|L2l?Xi3||~NHN0_SMfOE8>tf6kmp9lG=OBjKT$SvJD;n&HD|)S-IQC5DUcVahLrxq`~t=Y;Ams>nwzi*0i#N{YQ-2K0n zj=0vcl=}yPV_IT-^x*pgZHaN);CyHDeQ|K`(^dC$-`=yW=+)!k>*wsv-!@^1UBv~I z-{1@4>T~GcV#o4KJ?GK1gq!nlpWdomQ~i>f(Y{qV(fYfDCm)3uh&g#Ee=%DBQL&(q zE(bC-*1K`59nvf{dywG71(!R0pD!}k{b8w@ZuF`E3BeQNmO5}5pu7oisae01@43&9 z^h^w(Cw=pww1gY_7PXPQJ>@hGcgJoWt*nA%K%4XM3v>Dy3=3oOt;#mZ+wN+{`BphF zutR)LX)fL38l)g@xy8lB$asKab5E%#_Vr>co&8evck}d7PIn1w1Mqi`E^(h(E`dpB2%F`KJ#CT#xEM|0S~n z#(yvY`gpc4mi;wk(~BMjk?T>Ex>H}GvgLde4E0mg{e^|?Qc zE_#_lcQ1Jc5TYLp$GuA)o&NOeFCPHO14K@=ZrnY0(=ccRe0$;*|D1rfDy*&Q)K&$w zx^AuRkXF|o^7OE}^7P3^uY4S%hrVl!NnM5G)IW}->So0Hb>GoAm&`Yql0Ut7QC zk=O5s)?ah|rd@0O{>C(T{XYLQwLqT<4YhvTV%ZOchFZT{e|F9Fo95M5rwv-aUkoL$ z-+MwstY3L~^E|Rko#L!`QmY%N)E1rB7l)X;v8K^vM*N~F(4l$O`sb|0RB4{|phNR) z#2v!?V|h9FnN3WewrZW`*%I<>m1}UDd~BDG9c)3?wQ7s@Xp6A=+j)h~yq~UO#Lx45 zLDUt(6s{eIYvO80`Kw<%3631_XFS7q$pu56PT5R%ls3ULg4&{ExT0#2?$6jP8$J~| zBj%jlWy>m{de&bHrTWz7h+pA7oqnIh}ef3LQ zaC5za-`_vDk4aO zl=qp-@yYRyHu+bWeJ2qw*XKRLgwUsxS<$Zr|QrB1Bh-ZcVopz~Ftk5X`V((huo4l%c(l0O0`{J>({#|KZm;MROV1oQBiSr6KB2_ z+fo>$1ED-N!iMZ))U7b2DPZgWocpC|`T#ba?`g@s=f2K4_uO;OJ>Pw#&(S|Ai*yEe zpY0@NQEU(UcZ#C;99>0r<1W@xPiOFuKB+6KK0XoLslQbQ=j(5vit7;Unn0>WaJMLm z3IB;Xq!$C|um*5~^kZl6VrNj-H^Lf6)uLHHSxeQ7o2MV3RI-VF5is!B`2*q#3 z3Rcgp=y>qK2S=>CCG2`sc}g_4HRWmR-d+%%kR~&h9m%^=Ilm_x$4Xb`l@89A0R`4ildMR!n4d(=6o7(E0r)l z7BmLJJ}cH!v*yp~Tf@d9xGHKx`VPpR*{ z`un=7dmB}^U!88zr~jn0lL43wpITfUqkBFlrhn8itwst3Ls%}V&!kEv%ZD@hrGsSi zm}q}ui1Gch`blJ(+4h|Ff>KoziKT_@&a^#mKN|M8D*MZ8b1O%PW6+xx%sYRqrZPEo zfm!qQGryo|_-alENb@{dS1`ncCiORb6VSf&oh#YCVZYGjqjUrMM7{z2O=)C^*&X*} zBJi@~iv!BRzR-*I<&MMVhbs|Q^Q~L%!*6B2z1mK~`j$|K&2i6Jv&>$~*=?MCz06*1 zLpH2QF}bzqgMJM5p-ags4F@tnoPHXD5H4#C-)^oNRKU8lJ+H$N`Ud4FFr!0SVYIa9 zf89ZZw&b*tdDWpf?pccr53lC-6xDKTIA0NS#u2ybsi80TU2A@iT7QUIlU0sED%wDW z58pw^8?}z@s&!<;v1)O*&HTJP;C_3kxw)w`lwy}4cW#{SwTw)gj_wf*N^wVK!7 zg&Jore|RY>T&XNao%x+>TuOWA8a(i%-@e6UlJ8B-=23(FVuqmSH0GSA;_qAj@Ddb7 zK?gh#E0xYQmQD{Is4*+`0o~bEJcIO{@v2?@H;k43DM&Uza+BUK3@FQ&ouwKxs)`bq zJe{6B7&(qdEd!??jD<9-EgovmTtjaPl{`=8Ow?FW!AyBu=!&@{U(|mn6q~HQG_b1N zIs#IbHU$<{C^8V56i>39KpD7LMv3B!IW(1P}*+UH!o6w&qah8%vI$mBnhNs52%>#Au~N|9K+4-?yKU zd~c`_CMH{_xM^CxHb-8j^2ynbjbDIhm4C^6i(}*GIFtt1ClPWyTA&zMec^jxq;c{3 zh7YlzS}IU+cCAlqv0}g zU_oI~n^O;@+;b4m)F(aC)m*71=jC(5#LKXCy6hR+_@&g5gD@0%M+o1>?yV-Pw$5=k zS;e9ES7NbYdMx%;Gv4g1UcJ)n#FjaJAf*$2FZ^ZWZyf$6%$oya0)ayO1v;a!AfP`# zOR2ahd&2xV`k0@lnZkAtFj3&=48tb{tFX?TouAVbs#(tOS&1l86VG={Sl;vf4#>nC z!yj6XM}uBpM|OjJ{iqPmDc9G!UO$?fc;3SVSikFCi10j^rrqho6BJBf;*}!2M*&)s zF?SefBbr6g-cLhdB}Qx>2ZmbY_2*xI+%VP`^|BxM1!Ga8`XJfydAPn8PjC$*FMOH3 zqSFLBea&#s@!wMb>E{%gf;D)38d(IQNqb>Hy~&IqN-n}$0Uq z@l{VmJ3A!2+KeZn%}qKiEnjPYRr*`k4Ff($)>)^k9;)cD0OBu;Voak@5(9gcm<2@B zW^3ot=FHbWHd`@~Z}$BV_Q`AQ)$~*Evzu70y5OcBFZ@o`oMMsz(U6u_epiR7^nK-b zb(%^&<+qwj-(C*;sMKA4SDLBxb>(*{rcyh!OGq0C2`_o7HWV3vKMVd8{H4`;yZa-T z_wY|fdip!dd-*TTsc|dP`;fP!SH!y2a35sBeeg}geUJ$+!I!xcoa8 zAd#P>WQp+8dqma%{{wjq!(R(A)wd;H3Jt!W+{2!y$gp?(q!I6B(Uwlf)EfM_Jke0Q z7vaF{mF_Nwh~B~%Estdx)uUL#^>~5gcK{{*Bi$tV2Hsn;3O~&hE0<%*K~8;geCxJH zy7^9YNT~FjJj0W+8>G4A>ueZepl>YD)EgK_XX0h(zWgLNh5GZ8VA$TlZ&}k<1n8Gg z`(($xH_Oi!Zc!)JV;Al78=rFAORKUH+xvmJ*AcQJQdL1(`SJJC7wvjz`0QIy*Mz!h z+3(Kw9Iu>~?IC-PzFgc5FCwkDY6sG+_Ts<~8q=CNKXm1dB~Rn^qzxn{AZKMxljjl_ z`5_gl57lvzm%10}Fp6wMj#*&EYLxp-Ag4*Mh=UD0pREESEAc?-GJ!8Svq;H8P0~a` zYBiyw$O(k7o5J`VOTYR%+6`8c;tv)|P1W*i)>O#kGBP`j-%Kv_*sqgfk@|wwx4t5k ztgL72uaoQWWS(_K9=!y~#v4pL)sEtHRH@J9EUEsVqzOy2yVy_jtv-w-A-*g)bLH}| zZ?oaUfOOUSHptcbeT?uAxA4r5EVyUgzacOWtkB;bPmu205Ohn7FYIKD7qhst^|R;8 z-6?uXrW*~RzSM?PcAmhW;<;4kyIFBEMmRHy1iuuh#;~{9+!jaYYiBH;PO@UZj&d|Xtqo7P8n)~R&+H7_MP4%=acf-j@$d(8 za}MIQPlG<%e;2BE;tG2C2+H-YpT8~T`gz0?>9M?yl3zlP6xX79%WreqjPvkz)NL7G z$QR#V;Pl@2(?67=UmQ;JoOzCP-!2hEqxtY7gqN~U)VEI*9|FW(&!gF5B75usz)y%W z9q?S?-=&t71JELT_(sygF6WD?uNv+!_?zKKRef89FQ)po3Ev6Tw_W&}RbQp>MOEJh z;oGPBb_gFlad2JlR(+e);7--QIc!PSB7;1>9ZCbzHEpoRzg^MPa4AsGB11hjqG*G< z@eafkO=}qD@oh%MVaw~d&^DaGMhd(NTyP8S=c4EYt5!GE6WkfL3={sXRH_E}g)KHN zRISQ)*j-kwX0WGdQ#i}1)eiL(KcE(G4O=oq@k3NX0~KM*XfAPIcv7ZTKiE@N8MaT< zw4oks3P8C z#B*hJC-3cJf=RBY#W9+3MZFdqgmpD`-CFt8S^P%n=~)WI5O7nVHEfxTa4s!cRgh4q zJwLEXSFU(fpItPG{rCt)SIA)+D#HZsa1O*bQ-V6ul~4_|0IEx$>cp=bzi#~I;x|{{ zbcGEb6q_!K0rBuhy`i(^;V*eZtL!LW5CL+sf`X{5pdcnIC}<6aj73aO|5!FC#7phk zvx7u4sB~%14N!f$8iWwMkK7G@muS#VSrs@BPowYPkb5I6#e+HZ;(%xt78`m;HF`%B zp9V4fVVU2%gdhCw_d+YLqYuoOe%@|oAGrwXDrpIFp`TMw!twLE+4I3$#pev@gT8~V zz$exNFjV6DU62wK!ABJ@EOcZ{WQ%(x8(WlCEs2* zAkSwl`8vJI<9aXnRw#mS%|t}84m=qZm(sxas{RwgPo5m%NBH7w=rM6%Od#U;`9Uy9 zDRSyo*ba=|9BTI%t<)jDmQlbZ0KGQGnauh$Y!60}v;G`eQFqui3QJ2o35%r~S_nl= zc|JS)CS4_))>)C9=eL&J16G35&YTWmxh1^TqE5dWI%mj#&-ZZfNjTJ!MRJ>X2MYjA9QT)yBxICLe= zaraM+XLP>L>yfc!h<_77&r{VjmfOzfwXT~a--uc_ApyJ;Ds!9Gy`{v0Id8N$ENUG; zZ$h_$B{X>E@`k7^sN}qcH8<&Z{FsbsyJ1Wli)?hUH5BnG4Vaset>oyfw_6>dFf#FD zYC{8hA&MCr#KQTL>kBMwh7RI?3#{~m^}x;gug^WVkL6Sgtclf&03G5>mf7<|ExcPWY=1pI3YxKT2{`9snTEw4 zEhzJ7CtKNA^fnC0_X!f-#5OPdI>~PY7B%3P-us-Re;PxZ%oSLy3i44N`mA@PGnk9| z;iN&mXfokz(vRbKF)HtJQ0Sw6l)5@$;6MQ73M08!qyO`RPzej@C<0?UAAU`Tv(!r4 zdp`%gxzHMs`^!f-oO7*FDA8I(W;wAb-{D+pjUnt z%gx0&R)7;N%OX@1=aMMz>+#QD1|yv|D(l$qi!=?pOerk`|6CXf_+ewWHqx+dww2O` z;h#&x0mnY!)kp6~pq01TcI-#I=2kwqQ_@73TpWbN7@&Wci2!zv@1tCfvF((Bns1}# z<8p&Pf!z4G{IY^J8B4h1C75B8ZQ$1NO&^YGSKMWe0{Qc%5^@`{3U9h zczm9@+p+uF%`+G3u*W>nd>b|YS0ce^vg1Hs)Ym1OrwnH)Ll^UPN&Q)7@U@%&15w|z z6WW*rqxt=>ocY9gFt%^%(K4d|(q$Ld_rrW{KG_2|&U{Jzd1majsjnmI|Iy4R&V#Wx z*!O>U#mw)<_a^QNZazH4O|1;Z`T)SI_y696|0J_J%4ozksXiJNj`Yvx64mM&D@J+( zyYqzIULMzsmDXRMXoS_O82<55H#W{h$PWwZ?T+**FjlONo6BO34g0O+IKtc;stIVZ zfeLKsFV3iNY`9MC{Q0h!tUZ7QlMw&Q@5K&}qDsQ#5vX ztjNhA5rc+eWc7yl>`#A%oLrL$HJ8?%UePC2)~!8rCwjXj+X5iet1w z3OJnWtzJT%7EntJHaE$IQ7x^P3{4a1OVjK#G)-Sh=7s)^80PfRe-NktRhkBUOalKO zscHVbj2J`FG3SBOjWGY;P}972MofF6`8H}k&diq#K9KC4i_~&VuA(frfcIFk5RMXw zeJOY>PILnj8!>#T6t&(ud=a30T%U9b%$I3SFC)S#hN1yPch96~l%h+hEAFRgjH0WP zXIro3&shO~j$Qh5ppBd~Ru)=Yp^2Ok1lL>X-&^tbKKy-{tf7zOLRUGX@&<^dR@O=6 z+95v=en0Mn@^aFcoXaksS!6NIPWAijAaw<`#t-{TeWpR5MgQ|u7h0Ao>$O?}{9kqb zj~Pk-aMcC2_HsFjFId9`?vyUTW;LT1UcF`1oM``LYX2G3eUbE0kj8m40>x1_lu~UZ zXf|s#fALNqjgL|A`K-%Tee_w{v0?aN>Grt@1saM3)S@_V5SIH#E{ZbTm~p2Ut1@x` zU2!-AOQi9%V70{er7w9U9xr_|AV^8gUqT)sXdKc&3s$pLRcu&QWm`bp|CmL^gMzVm zg(KttYALCfk}VS+|5rkMc)gSV;dTEe@7er$L#;#g+^;J5E zXw`<{pKc;2P|^vV;v|ZalZYKeExdFKPr_c~i{VL5+Q>qRXaVe^6;9N941bGr4Ngsz zcG6^W9T}F=XPrbNDJ3_s?rs>ZBDM4+R8fjy1Pyh4$5G!OMUEODMP5}u{8Kd0s~!Ze zwFXL+e+-F#Zw>VCWEi34Yib^#2h_TlkIf$ceoDyT|7&Ctu{9Kol1a2BsfD_0o&_;^ z$1d(VTJ5|QU%KwL!FL3^4I4zDeaKw|!{-hwSw7FvLd@wUwj>-%cQ^xv<+ISan!QQT zL(D8F8N;a*r8Sy!Ne>-V6p=b;*_NdBv-=-y{ak#d?0-#k4@*8bnlz7ZNc>-G-SZ!2 z{q*)HF&46S_WpBq&wrZr)5D*X>Po^`=f;&f=~Oa$CT6&kj85oB0qsr>PHz6f@Wkh& z6uYMgcF(klNmo*YqDfa0%$~Uuy#!kgPt_Nriwv)l+#fh@j;O(+3<^mcokw@bScYS> zCvN`0Rx>BeBW%ekz=3$&4YSGE_17%QPKcuB<(tBmuZCidu>Ezol&QuXI${!*kSKPl z79omTagOJ*v*bjm&KX*TE8A*On<&CN0kp-brc?Dhd5e4q+n&S$+#8`5>3Kotx`o(S zRteo$&xMl(POl0k4j>HoeQlrFyJZxpjONs z9|>E=k15h|frXehe)kxk6WbqA`3Yu3$>)U6y3PU?tq{e{g+PV3KDQYAzkwlk$Dx9N z*smPX-;evL#`rE07M+AeY+l$kNPiokI4%|)<9A|P7@7k9pamrGX2q*ah`r=jM2NLy zd#LQRY3)?cCE`!_{_vqcM6oOEDi7NShMsjOheHwW5<7Kqh8^D!%siiW53}~%KO-F`1SI> z_Z#wlY77W@5+B>4J-B>?88c6wS3ql3*vR~76U5r_=mfJDcO-Z&*!HV_D`azh3}p*7 zoev4|$(g^aKKDPkK5y^(s&~_Q$=>G!x0$=2=hltpuRrv zJz?sOZ!==@8ik-!U6}2pt?>}bOnG(K+Fy3ftZ1 zBNjkx4sCcxcnQJ?x)EG0gSqGc>JKDS ziG504UNf>1xs_joud?)mf4-7 znaojQC!u1nG>aJ;=l)Cb(;@kp%FB12AOUq!fyekJ=uO?ulRX9=l3;J?bS zpQk_lG}Yxsl9kcxjxVOa8HSqq)m({GQa|V^`s{Q+`s`;o!IGlSh8|}Y>_+|o^GyG! zfgPZS2#Q}T{p!yip#3H=qLTn1P0F~UKYB8<1!)G#rn%R=|6oCqUvq)E@XLFE z0}@*|u*KO*2e3zM98@RrxnS}_^l$*$VOrjG{}brs1FuLoj=LhA&%5Fmf?o18q!!m~ z1m^3T+UZCv4pZV#&uv<}70)@{X467@I`cXfJEm#i_X5Iv`kd7Fz>3d)5(iLv=;z85 z{Y<#@=yl~pAHDwNqb#aR5Pa@OCa2k+-M;C1{q077@66tX(%j|#wrh9!ecUvW6_|BRd0n5B*E{=~ zi6LogKU6=}E!A{(LQT6;CSI2@@#<&JFpo>2vaaX|uFqcoguBP&>P}9sDb;zCb19-+ z-7O#QHf!!rDERO7H*2b|VAgy^+Wj?~FIRdE1^?4Ofwma3TyC>8Rc&wR zKL5?U-u!p-=|1MavB~j~ZD>NPp$SKvVND2C2RW--0m$>u@#JShf>eQaMvT_asq^2s z#Qf*)Ise5|^zTJe-}>zXS9{EVtDa+hL#2)R?+br2urua8!$81&k}~U76VHEhkxkBj zWSIlqKIgxyrsVwRzotIPP4a78@A)q)W&Rs0=RYSaLOT?pEoJ_*8~V`Mr4Ma}KD0@F zh|5=48G0{BWth?L{Flq~-;8dUS0CzYJ=OdEAw5H?FDlp8*pWZ%eP2nPR~Da@)R zTjX0nJE*e=pOc6bKA!8t`K`Dfab0%Uf~)Ki53F>fQFIjkH;dYPWF$>p*}VFF;B(!U z#N9Etw!GNMzce2tfboXF48=^p(gfP56Cf||Kh;xSKJ;8a@-qBXcX`Qv?z-|KuRQ=e z`jw$wA2fQRH$5{_=G#J^Z~0m$VjcvFSV@v%PCT#Rs<;vxjkV$!edX$&*Qs!Mv^T?O z&vS|H`Kl#*bfw#%`{g*B3b@AW^-2dbpddy`;{tkSj1>a-W=!qyU0}T&V@8<)$)Svs z0{TlQnME#Rwx1Tz|9Yy6o7o08cQH42%d8Q}&BLdt1ux&a(eHf~9n&D$b#4J#`SOpK z9e01A6G%Td+OZ*qtX-sxO_H+G6rLVa>X9T#@t^FAlv@DpK}xp7Z$grkcPB}imO@Iq zTu{Y=4I`@5fM zrI#*_qnqDQPm&+&Q|^DcGwnvkS7b7euOX{?jxR0`d|RgX9$#LAZ_0});|mNdh!{e- z;K{y(a>|pvgz{Ygk?oum%CZApz0t~0W1Q(0nRTq}jd=$W(iq|1xW@SM_8wo8<@o9% zW#XSx##aR6%WIGl-q#l?>-O~`W$8Y~&z;sq$}jhKk&>I%os?T;);kU0I0nKDHYhTs z5k>usuW4zC@ud_e#+Nr)z}uHRx_cN;Y02?r^Ys+S>JvPFUdKPUd`OCa@cQ!n{rC1O z&(1#N8COm~X6e$%fK_CQLJQp-DFSxLw1^{|8G3$D1(wMlEBWlwiVGiKx~x>R0-Tl8 zro}RqATH6UxUlS#cijP-cdUvsFAJD?6_-9%vg|Vu{c#m92bZl`%{4g%E=_w+=(9^d zQ_;3&S?OJgTaPNvFI)B5H7IYt6&JK4AKwnut$Nmxb$ z+t?5h51tGMdP8lng*83H)2^KvYOA9%o>~<-$)RqBC6sYkd(r9G3f<%+T<{G4Tx3B= zi#ctrxU>@O+iI2l^q@>ejpw*%5H)yO{3cDe*^X&vZW3Sx>ZKNsdg_qNZJwKL$Hy?# zm=2pC%kZs7(zUY=?b&o&y$3qL*65jm98u-Gic;yogK%vas=bh*of>M3dq9(|Nz4Em zhfyzTumMlxMoSsBiM!HNz{ElA1#V!k(^jjUa(Vzm$%Ux#uxF2onr*;ZIhN6&-GQ)U zYxE}V*_#H>1Qh&2(hJZNh@_fDCy&$Qu2nh{kHmZ{2vc#b|3k~kQ`WV_HUC5=+3b9<$j zDaA@nT%a@tnjVzdu)IE(DH}@xa&ZsT8!?m!_8eB4iIpmtD;A=|_CmHGhT6Fd&m~)F zHgLk_JGN#I(#>FU`dld@>mh$ObS()8Iu%dj+m7ItT8I(^7|XVdxQZ+y&VBfj4c&-1 zgnTgg&mx0QM&r@h=7p%URMzD?jY4BT9w9hYUem=8mhgRp*=g4vB|Ps z@SF$MV}W(HI0Dfe#|Ya|qcfuoI61bSM72n8YtK1t^{9_sRBdBN-5OTfeMKXr*m3l9_VVnSalo}cd882&RLBc^v0*#kv zX(ZO6Ik)GyjeHlaX1_C|S$oljns4$vr2?j%y2%!`o%f)V4~m6ApStyc9M|9nqh6n2 z@LsA*G@}-9*u{gI`rQ@>iXHWQf9O6>skQ9Ah53#lwd$_b=U53tJYg;gf70-=nSlhMjz zw1{V@4#)v1TMhRO(Bi&Eo2W0-z{}MOFBjvL$#_8tQboXtP)p$DX1uZ(ugnx~ad#Tr zS_pji*pLrcxicEkb2A7>M(S)AUQWi#Er-_)@rybDH7T_;If=H61Ej^6b1ynPPXR;Q z%br%WMPu-|rwP^?vX8|u0f+}V8U)IGUg&dinHDJjA#@7`iZb?5}2~cd4zfMBr(-YBe_+2HNk;q&r`@u;$e$wr_w>sK~UrtHLxsz5=27O zIksv;q1*=}0w!q+wR2=V*#$M8PPC0V7wsQosUVelh5a~tp_0(sz?$??E$J9rqaZn` z_cTITLrPS{GOi@m5*T2pB~dRh3CJPhY4tRDB2?cM;w;putrp5O>H+W3qR;AqI$W%- zwk}cwcH=tY<(qE(8Scl%-(P-eb{@yyKK$*#-@O#3|Ndq6;Hv-Iga14BVCk;^+k^kN z2VWa|u=7Uj!K@pz2Q&M&2m3d@412I2%PVOQ-r!7I!{A?RuBD=mnzliRRxA0}C^YsZgrC&(1&hjx|Vn41p9KMgQ zg4Wl6%FIukZRY)6V!ysOC(Xp)+R=INe^puDJq2&uI)*e<;@{9^cgdgmi@Wit*6Tfy zlrIQF-Yp$q((i0IKmornUc$TR-JbG2W}BpnX$4*LK^|xu1KLI>X=DH0_30xGb6B6S z#!MI9J3&$V+q)`4e!#nV&=qt!1H47d~sR-ez}>%V?z<|_|-4T=*H<3J&3-JQeW@*kc8#}nt-)@Nfyi^ zSixw?_&4XBEP10i3D!TuH-O`7ykt6GIg32R_d(3}0^&Pwz%CtJrIf!lZug#3s-}<5 zrjE$1R3K>^xTS!e{>g->m75rWQnaayX>>n1hXd%a34k{cyq3T3S&Ss4EI`Ub?AzUD zByC2VWws6PiXpZeG3tK(dBm%xQRhcugK`zUpo5>&%A+kJRrZPAs<{w=rb_%9iuWhb zF)7fuzN<^1Te=JMn+!Pm2ZEb;yj1t2CFy!K{!6BtDE%GD^wj>HmeRjo#K=0oEY5dz z%2;$twm2!TWPgUg|K3>FSo`c6akx^^hplGD8U1mH1mX(uas$H2{uoRB;Tge9H$bMh+ZhOXFYro zbHqG|gMg1%s|m zb<%@dxV8GuOe{~c7O4wdYQU`)X7kk94}LlMmK??}CxKs10>7LDemOnx%SqsulfW;> zz%S?T$FGntOt-cjor7)WGz@VDS^(ccV!lP(=8}g%#A2&hXBS^`irX^riYgxqX;6!H ztHlveps>0*j?LnhOQI+fR_#!G-=ke`gj-IC5`wgbXJiyeyuV2V%5!H7Hx9LL^h}@6h&D;~>BUx&3gZPLWkK*DO4{pR4AH;0;Zru8<`nG-A*YMU) z7oW(0AXvogY!z4)ZO1+1pZ0Bkt6CHbyC&mWe$~HI*`xY*f7-t*14pMm?Q3}}J;Pg! zXK<_AR<#iCYt^D?+p2A51bvZo3Lm1d#=+gfALW$O8I7p1?FEX|Wi+{ z-6VX~ZD)la6<$SNwFo!;52nml(~BUlhr;&Bl&k}QMo@fJ0|#RiZ06uj1a(zr@n1x- z3JnZO6TWCD3U7#xhp$Fz@saeRL#-%o!G-=|`zTb}EE>@`kXD+Fs+%cvnnF7f;x=9q zWepUr&S+GMA5x1qgO&{c7W8yQEwvIlY-)SKvHj(dByg8ex^2}7tz)DaF_gcI*A9qT z!3_-9mvI@5aBw#TcOaO7LYvLSt-vg!V*si&;~IF!_J$E*7y9Y}VAl46);>bCierrJ zHl>wtJO;cebRUIIP$-5F@aAR^+Jq2lKc)m95Je3cc!qhCto?{7Y#;8}9v{IESDYs9 zR@42G7lfvDj%Zu8%j}D1T;MC>hqtZThZxm;0j+RwHwBwHc!+{K5F|7%@b9LKwgJqR zgP@@qOsUqcj6_{RL!)RaPCSng#&Ltw%?Qcf+(Dsz%zX;Q!SS+cwQNVm-T{)+sInDR z?qn|S0+&TIu{;KuP?`>^c?t&Ue8kOFl-i{4?<;X#?%A8vD_AIr)4MarQwww<2 z&TQkDR=4+s9!RnGHuIhq1nxti>b~r+;0Nmy3xZ#kK?T7ug0$}#(ScPBwC`j&iabC? zc4j|FKifHm_3mmF`&8*`1@aEAvJb4xHAQw+XYWgfp6-nXE?zti9fImk?d(e281$TQQFS8)sdlC z`g%46#eLjWWdDyb3`MNPZ|AjmeBE2~8cW_R4&)qpqL1||zXyb@#*%fAT(TB8tIY6Q z3uJ)>j+;>eF#6rX z^d6=|W1N4VDOp8Sf?7?i-fo&WC0+p5|T*} z$#VcVNnn-)7E0h|33N-~3<-Qd0<$GBAb}4NDZ8?_(+?avGRs(*Wv;K4^AxD*|)P<64e;cKV>9rmI?Q9&*-1H z*x3otGzM{s9so#4W+=vx0(*pHh9cQx=%EJ~!t62B(L)Sj_83}e3qzPahH~1<5N40q zDaqQ!gc{yBu^B`f`b)A#kvuch*meogB?SBUKA_TY>j+!Y)m>8lX|OeM=Mr5###yqP zljAJe)5&p`(%Hs1OYQIE$VzrOkE|ZuZH%m*U7aIoF?!qB=B#dJCK&w`(0?(AyCW_Y z-_5dL4FF<>ez+=QhGH<8IcDepi;NkA-%2rK)bC1+X}bhYAU^Gq8VqWSfjrDr%E{g3 zO-fbHPN~NlRSDK#cLAtMlpdRM+-zz)yVAt|e%ZK+84sWgfJy`sU;G&NM7f$(FX4_$x=NkeuLs0*w{*R9clM z>K-S&=;KAGi5EZzMu-axgXyW%8%Ox>$T*KIW4TpWRd*WJHd4n*Qc#rgQ~WZZO9Uv& zXh)eWE|bhZPDrLAH?@Lt3V=vhnnC*&7NW=swm;3FcRgp3X6*4{NoF7TwyruEm zDnK1s%Ydjmd0Zgzj+|C{%&!zA???IOWO-U?w2w@d9Vg2!LD>_sY-ytGQq>sz`vp3_ z4`Uwv$Hc0XcPEb@)P}BIfznwyaiv}Cm&G8LI(}I+nnsf2GFih0Swj|TXpyR>QdX4H zs+=dGWi6wB>?Ic3i#+C7hbm-h+?O;ax`vyQVow;Oj<0i&L1W}8sU`&vKxBiimqW|U z4U+XFtu5l+ys-SDqyM?Zm@AkGMpg6l!xG#zspx;eSTN8qCXoQ3ooSrSfQSS7 z%p5c6_J@*N_>aDx?C9S9@a&ZJk=ty1AEHGMjP3AZ*xSbUq54#N+n$EK*_DOT-tJ{= zE98%cshvI9?iEMi0k?k`h+_^TU-webN37R>^8({daDbNpypuUN`J6!y;!O7b944Dn z0gXu>S&4H>7wr~F`|P(f?c=%~$2jr2UgsC8NmBaSFaEG))Ig`)G%ieX+jwU*xo7;E z`Ms8Y3m`w`L>_B#XDnIXWt7MN?ZTTV>@*7ZRo=8k_Nbb@ftk*k9^;*_cAj` ziSvb*y72xLY?7cTfr?HG6Idl7&1$h-6kilm74VDPg;T*stF4Y)S2b`qAf+tNCtFvPgv(&4Sz}UFAK-GhGRWZ@pwB%_q-} zm^o2s;)|1P^`*YLY2$GiMI*oH#?EzbDjABV){IPiAEZ>1Obre|O390G^Et!wymiw9 zX0hLRf8Q$RWuiA{x+N*vxsl4EEKytW9K}E|E^1mx_CUoc13)`p#msD_ArSpX$-dT*kFYryEX>1vaN>fBo1ee0V>!r z0%UljU_FckTZ3%|Y6o9wKZy&^;oFXgMPtPm$0$jYkt)l; zP@TDQ+7Pb*)ZYs7kesKLJdFxpE;%9!CZY|X1d2uDb?s^qMSYIIZbph+^a|2O7%5S^`!M)-vc>`ZP zCk}+pw9eDtgF@yY70P*L)Fo=A)>cuhzkN%bGHqPTG%U|hM{#D>VCEgAHAlfi|ILK6}FGJ;q znTdnt-}n{L!`3Nm1SZIA5EObpol7$X-_Y&wnvRN%<7!sOUs`7@g}=gQeS}gO`MwUn zZA1CK4!@Z?V}0hov!DDhi(>jmuYrt#&rq&&PcXY%o!KZR6GT3hgL#yQ+7VS?41tr@ zP)FLD0iMVry7SKSR9n>Bb_t)8d(_q3(QjRr&S+l!8mo++t49@=7K<8Gcb)Tr8$0?Y z*>6W|uN(T$COR~!oxqb%Jmu{bwi`%~}@CR5`3%&hKhuCydFhkaKAi2|jApht)=`Xm%gxzEi-2=?5Mk$mib z&b+Ws$BEnfX`|dwefdD=6S`tDEq!>LbnE<= zwLYk{W;6<|?Kz~>wLPcan~PjZWBA@&QvP3=fEdoFXYp~?`g`pr`CsV$ZsHFN`|V)- zBe{sw42|@`g^U0AK&vN^q~F@7_dxq0gUi|=#w-_a$seHlF;w1 z?DyaJF#ZMc0sR};R0sN)@U}As(FUCc%}G*MnyydmEu;QUVw04DZ0N5iKdO5N8^nHO zRQDd97uw%x)Lv?*It`h-^f1x=IAOO`3?=G?y`n;+YU|7?1RALS^_K#+8R>_z9|i{z}sv2r<-MH1|7{82&Q-oBKpMi;%0zH!Sy_;Rsjx z9J%*o5O9#0%ZKJ$OtTQuB=TK!C23sh1 zy4=rp?&h5R)hM34?BP4fiNW94yBhE& zuPWT|1qh^))O4=Xs*zToYEcWR3YN`Q2t*|i2BFoBfr=AxYAub-pK3K!`*Dd@2al-i z5fv2`wQ89iGEGWtJE)M-3Z>MMO_V^ZgwnO)XRYr!_segKGXMYfjP(9}_n!0KbI(2B zJ@>nJ70%LGEZg?M`eZm6uT3rF2DC}1VoOgTm(w5nA_FR~YSAsj2 z*Kc-(i^i!9D?NE(F+xia9>>yLm{Z`U~5S_yn4HpK2r67Wp4x8|puCqZfpj}p7&K;gL%eCMRin!gyi ziQ!@<7tIt>Wf;J85Q290!Jv-SnhOuZ5CdK@w>7s2PB-Z#rzW%9M7$|y69&pO0O+8k zC?#dMXy0h~Q$1tje4fb;P6m<{;h&$DY2p;3>%%{!XbuV#OyL3>!oTVp8wYqemOvi69f*Nxof}Tt1F?oCyQ9ki} z3gqU{vSn&6bsS!} zUjzvmE7}|bnjaW(<=N-w{J)q0K zrP{fu^af+X=P>%%VYhT5SO%r!ZnA1er1F_klvM1BpOlJv!hiS-i%^)RT&a6Xw$WyP z_O^n!93L;~%kx2am$fWRBPRWPku~LVB%%ZI83_Y-!1;{y^AiUPlI$ltUfx&_LiySI z+w5mDT)bac#5M?f-muMiX6CY~{iXHJGqfc*f-S*kwEfI^n=Ek(4AGeO{`0-~=&kx2Xr)M)NoP?fNXN=zxJ;mDN z|G55ofcxu*L&^R1^D$jof9=;&I&aM$X~_6H&A-#p&6CZ)xuEAJ^KW*>vzUK-p3(iS z_DGZIFWV#Qr~IAp7=31PJTjlTDIVvZjeXX7L-%iKkG%Sie{XxF@4D_*?UA9Q6YY^# zb*0!NFYZdWNA5iFZ*GsAz9s<(U&;K3+9MxCJL&ewo+D}Y$l2p*_QGsHA@b7Go z^j_7aoj1x}UYz>-$#MMmiOuiu>EE!xp827-VL2FAEI5Rn4gj7e0)Y#9y6VI=;`Nu~ z!|qQ$m2nzAfS|8zBoL<9I2s9^My7&2hJItPK6`WEqM?5EX5EsK(W>TkZTig_;_!X< z0Q?Ub0e)gWHV8Kk%>W&?aV)0WM&^yrJA=D5wjPqgL;Gn1_0I9yC(jla)n0g=>5*W) zbIf~jCblxx+n+%rbb4iA#1`0g1fq6H>94R__+V@7C zPhVQtmKS(bPi~10pMG9fxNykWhL4s^KSXq=4(azP0YHC!20@>?{+r_+%tiyY$EgcO z@TL42v}LNBfmI^e*1Mn%v%4;WFQ5MIm*Y2kr(E36f#aci_P!}td2P`nJn%ePsB=fX z{wZA-l@^|`bKq^jp%bQ0KT2X4(l2mkn?7BIFntGU(@FghFa&;UFg>E5z7$T^8hC_r zyjQ20J|(D?8iVNeUYOQ>(fbrWG>Q7&_OyVk#81Wu% z0bRbb8?$>sqY?2}Ku8l0-`VV|o-16ZQF z%|2*w4<|!6oCe)s5_BI)g3iv+Ro6@cTQX*Y-Ya*3@zFD&jOjw-L|6Anu=cmtXZ9km z_P4M0If$$ahS?nqY6r-gc^XtXbAV(5IizaH4H(emz%=|oB1?ug-!6`cmclkMl0v{n>d8Ie9ZeW`CN})IM z>e1fOGhlc$NZfaOe>-L*pL}5lkn;M!YV1J7>wgryk9Orz#CZDA1w8V-{-Bnt*K(WR zh799r7`24~@8vRM%jjvY8QHj=sMqvJw`c*tl$6(DdL&?MxpN#(cwP(!;LzKE%5cW@ z0a)bdT&Y0k+57`5>6WSXX-Eq^ISuY=#KsL(Io?Z#5_jh27m0v4-W`T6t=G?dBP4H0 zi6?t=hj2$OTpxoDEx&_xsMLJ87RZl!2#ez?+8EbwS;!Y-b%z{v_F>Pfy)`$moc(YH zg9=DT?D+PVR0 z8=DdQ2F1s3%Ym1G1wdN*^I^5jzAUX4Tvs#|2uUBnU4FB z9$y-%<(b}(0~Bdnf(i+vdkjx?ujah10k-)8Z&<<3jCIcWZQZh4EVF3rflKjp(wPtLS%kB)>@D6q3AT)HEPg%&V0v@o!x`oQ6UvygGT_Xq%%C#g2;M>N z--EmEAUyPFZ#6>A`#4Ik`pXb9EpBLvFh(?4Fg*<-WJ=^R?(<2>} zrSPvq39O?=)A#`g-~(q45D&M31OuOvpq(-Rx+Ck7P8ndblb`3uPq0qG^UtH_@j~`` zB~Y(_{TnfH<2s5<>##*3@jeH{Y-dpRmBP-;DTUF*eHo7!fWPUH)zin7(@I}`#W+k1 z+PnLEh`8JjgD235fTozv-$rHF^ON*^rp@;uRIp~eunQk*w$v{fm&d5k0WnYBch9;B z_Yr7&VQQnr?@b9H*5dw1XXeUqVB&EZ zG5eM}oo;TSJIgeVmqb>T`#wC5Eq?%JMoHB4>CaN;slp(WtjBwTc)m~n7C?6Q_-%lO z9-&K9qp-)oGLPZ=8!*=B`V4Tb-JW5WmuJ|Gw4U)K#pP0M_3Ok@(GCmEn0$nIxfFlb_e$^m(?Y)+g+#d*cEArt{SNOdLXbBJD4YbA6g+P&7O>UWTKf=pg(zPSqJmIn5WKdBT zMgc#w+VwTet#rjwIi~z_T5(^72yePO!V-ee^>oZ_V3O7O}W~YUpX{;CEEOe)+URiY&TnL z*GvMridrs;w+wtI_b>IFlg&RHe!ac4;K$4ACp>fM(%7rxTV770%m}bueD_M`9u1XZ z&yDndYfXi{Ban`p@td#Bv^lA5nz+qu+2-qo(@bs7<2K=mK(p{f#9Cg3mxFR{dl{B` zC7*-8)f%5B8^3A$xs$j5xl>8)zgBDiRowpFccb|~*LG#B?QKsd58>ualD~=fEz^5S zo`&iRq#H-pzLK|I#WzM?C`qX<#eelmjl!3Xd-4-5ELn>*LO>^Pz~Y)N<8#}T=U=Wp z{}O`L^=F?wfM+MrpRduMJAwXEeS(3H;L!>D(I8o(WtG?e1`<4ROn%2WtvqmHnr*x= z%C_GN0>X)tMscZJF>ZoBzU5VQBU@fkg&W4lx8#A_SYtV&G;__}iSLhcW9wH_&~7ST z1scDE)FkX?^5aZ%+m$5w!R3P>CwYq{tOc8&hN|dO>*mmUU%TpV5M8L>7*Kc8`-JM* zr9QTi0={benzqiF3fY>X))gT}$5Yj9;DAA`ThD<^weDUHnAN%p4rHr!t2vOP*10&4 ztJW>!fK{z?a3Ei;Tg-t1wXT!{bJV(p94J!jKE{D!weCR<%vbB?b6}xbSBwDZ3;6uj z0@U%+&1-P=iTx1yZ5%^7m`yOd7Ss{#RfSvhu#R6U4p7YJJXCnv=RTwaOSfe{zka6e zaeM@D3A@_ct1bx7F5lWi>H&u2in_J|C@IMS)Tt`gB~ z+V`*E#1^Gy4-Sd3omHIM1BY==hjLi0*{dSOz9-<%RHA_vv+XRBaKK97uz}Bzu|bNO zl$JpIbeynbvu~$z9kwpjSu31Pffj>uM0M{G?%j&J-ZlhkZ5@F&7%k08TOfc(nr-%a zdL*cG?nSA`^}quJglC89Zl;4l_bc|Twg>@WZ$u4vyakUp+U#5LxX!-c z=Gl+ube=}lvqN|qZI}#q*z9`)esiF0y3USIkah^PhS9TwAJ}Vi?hOPCI%hM3(QNBL z#YB>GJD^dH*iHih@Q)_2p54f7Aq`x2;~XH>-AF|3*2vhcy6c5|4<+pbMoJ4|)+Ri= z>9Gh-)bQ*Uo_&PIka$A%>=VqKt(Vwp4;-GZG1kP4;gBGL5@+u0XV7h3~{Ma z+QrWKoR-OC>`@?N6g88W*|#f@G>T^P$xrnP#EhajBw+Tf3S^9;xpC=I!2BXBARx)W zK&0G!QB$it_A$!cN#rY1q4<=(Ih2ZrXNrQ8rjn z7v+Ehbx|(*O>Vri>Dz1t-YGtwNnvbsuNI`t402FxJ z{Zg%YyI_cydJmVX@+njj!GOQ8A8#bkDKD2gWj6H2i-eE#L16%8=zLUzJg)}L(i`+8 zQCGnFfml`@MZ)(W2a4kxrEl*~cHmBSAF^gV;Vsc<#~b8#d7E|48f;@0I^@$GfV}OZ z%)nmlvP}Fb5@lv~Y?o#85ff!Oe6BUu*TdtnbBNzBC(u9U0m|5#ecn(9v<6q8qkZ&YD%>N3QZlp!j9H6K-K<6XKO; zk~zI)e!ue%KA6gGd-PV=y{k`ScQSsLCHN(eywRSmy~3Eb?qz;q z@nnODOd=X>Grd+xZ@%QbKyp4ua$Y1kFP5CoXU-V|xwWBG*sX+ZoNusVzFTz1@JQ#M z`93?!`*f1-Sf0o#@Bck5Iej+#S^wVr>6krK!2B6*g}?EUTjQ^~H_qQG(U12*96^Sa z7Pok>UVR{6PbO4!O0o$h7Qy=7Y`~{VG-s|dLqi)|Fg>Xrd?&jLpB&E0$bbnx3+3*l z#Szn|>Sod={rBs9pYdlqJ{_}7t|M_MS|M|X^{~R#$pT{!r z2P+tL1*oCDE{b0rX{5Rv2(fNr9Xo|X(8XGs6(NN~`7#Ye?iDMGO$BYBCWtz5VtQGT zsh}NEKebfA$RJiU&N0A(KaUYV1S2OhG=u{`z;J+2i8~2!!eNYYXu&_6y8Dg} zQ^8dKLsQKtSISl0)`-~srUxFs-_+9u-f5acFre1uaQ={5XGQ>zM$|e3C;eWn%Rs>E zhhS_9;@=RUYvfjsnF@ZR?#$(4-zTiqo!R5`o5{a=dhA37Dtiha`17&>9(9c~>VC;Z zB`Q)^77xryx{tZweYK{7?)yz+J0r}_rKj#U&ChtLc?TFN=tug)60F0>s&jD=%vMD* z@zVvd901z^6l(!4ggMm|k~M|6CM#-U$T@9@(q1ELZv|zw@{z-)f+wgg>H`!meTEAM zw6>;GTX%34`Am$QvqTOH0c0so zP9#RoNg^krk%NZ*937AbrlV4}8Ra%59U7wNF$hAk>E8ku*;X{x)+uT$io}cb+|7_QsM3FGjK;6K#Xzf=r;P0zN-hip#my?1Hq-E{STI3(0$DbpKIBj}4 zrH%DVBHAV)zz*?x5=EXe6`UdhG~ipQmZ_46Z$_96$O6$~uT2p`?v2=R>?it=@|&9o zMmtCi{+Z4op+sdYpDddb*Edd#v16R26{DZ;|*g&&9|t)x-9?W_LXaj>*jX`GI-o(Q)K`YTo^wLrD6Nz0e zDcw&rgW3e86&ec~{T)nl)|+H%6On`V(KyXzUcZ&vr(OqFJatKc_hX4e?DJ833KAvy=IZA2)lJ_$-_N|p4Foi~~BSs{iwKSUM6mHN;HrtiyY-_Zv?i3R3_xhMj~X-pKU zsLVVio%B5r4k{&?lTrzbMGkKM0~>|<-GDbwrg#^?W$~8s#A3@mQ-HTvO){ot$R#1~ ziSbX`_wo^9_C5S3AR|ru2M4H9WFJS`Wu%cJDumy;0|q7b)_x`rwtCe5e^oNAs#plW1SaaRfTrVnNRS$!C0d+}IbH9u=*NP?(_CJIIN148= z%hcQnYOae_n1zOmc^yWb&o6~>4F8Up%;i>;IgR9?OvdF4b(-eyGMQHtA&I6@Bu^(5 zYRbCHlyx6IpIT!j`GbAxEi2Mt3ov%hK#XtGome)O& z)PDxrh+8#(e{4`WS;f&J7|bg7N)1Qs2A3#Vbh)K}B2U_oyW zzP`@%*_#(Y=XrmIGFYTk+L1V8K@C#A!zsIc&gQ~ncJ?FVUJ8#1&t5F5V!SO43KaZADL&D@t-0O4gTLA?E%mmPN~u{q4WDQ`8j-E@ z;zel4v@OQUi@Eo~R2As$-b+)?%AEmKR}4OI^b&wj81Lfh>P)XV~B16&aL zlHlfi@KzWtj5L4+<;WYi=@-n?)$8Zl{3Z5XRRi?+?y7VA&WwV|@61@$qA#u9_&C2Y zi{IXZm*!`=-qZ9CTkpB$^{ton@wN=CAz-UIRwuCLqeRlz3TiWMy7aTCLoOKni}}6P z^{v;Pp1^MQrBrrFU)-GERqc}BXR-eC@36l0>ObD%`cK<`=K9u(KinFBJARqUAD@5t z;Ild}F`vszFRdumr+zw^aJ0tD=W==S`=clxn7p*+pKM6+PeS4oBZxM)8QV=;zpCTU zS71v*eRrD7rG&VBkWV0tG#gL>();gkXj?pWFryTEYpb5F8;6b`gN~ntXSdm}Nyo}I z`&G5BngdbzBRDV$S0e|o{i$}F{b@Kzw&8OVd;R?lo3efOPH~ic?C!zv&zp#fdSH$( zrbre;)g z##O`kS84C-UVx9Z$#+ImhQob%Vn?%vMbJ%ukiqVA^ePlM9k%;;Nj5TOC(b^`!) zX9Xp@pQbd9ujcqjJYLQ5(RjR)?+<_I$9TkD>vIkOWK6nOw@gQJN!Mnh zZ}}S#E5;ttBJnWS^cdIT-p>x}+vm-!&$PgDsrrLpxCFz8x(4ntnekp_o+XU~`yo@7 z3Ac!uwJ6?m-rR+_Rg3o{{v_f>6i4{7U_7xswrpDfl9hm$U5q4X9WsOCB;s|eQ!_Zu zf?l1P!EqM!%G3;wv!Fkan!#}v^o^+*h_k3;5VGtG=T`4wKM%v};xL?gQk=Zp31mup zxf95`f@uxe(uB-ii!XdWbH6mOuVZZ7gP`b@V-iB?(F&Tjz7oBg)_cv3JX~xi>du(9 zJ_q?!!>2CNxL7gnTl~WBDMxYouF+@TU(#Xno}lz4N? z%$A%Uvn8kbWlCAhkW~DF>(P?gmXyhiV9cB>;qg+n3-{>=4Z8Z0?#<5!bA^$@Xan$I z`*9Z8kEW9Dsz0*MK=yr;?k@z86I2FijLScl8sldEmvEZ@1=GW3KJn4hAl`xtQQ+rS zYj(kB0WXYcYZ*>;!Z0IWp<%DMGJ2SWoA5D}=+}#m`gUMS}GiP6*MD-%Sf}NT9WTnI52mzx^)KY0&~p z9KJV~BIPnwc$muZvJ&c|pKEyj`_dV4pqBs00aNbBn}g3m4_=^hSKRb&M&!ul9i|E^ z$Y$wV$&kL42-mPvE~Q)Qa@e=>z*x+CLNAw7IJ6<2R)LVhp?kG7+@&STi*Xn13M&>f zv9v(^syt9QKD4(6Ukh<+@A-M^qmzSs)=u56XqL zgujIuPPl92iZFY663!c|wo=HH%tyo<&?kI4gdddt82v8e-^Kj9kO~rLJA)D?xmfmn zm#nl@K3&Q&cP-YEXhE9lT48-uI#Yapik25+p|e3&5yBr{*WxN7{Kw~_ua94tc>g|- z!BsI<=`pjH96e}`JMczd#;~~^RnR2D}U7$2bg>J{s z&yf!l+9MGqQq$q` zK_;}KzeG_@V8ST9N7DcFbS{q~+|zPhF%YYjQPTjUu4ilrwM2CjA%oy)kOj0JOu^|` zf*dT$M`C#+ly@K`pN+%;I$%v;IEyeO0C?G!apY>+fg>JF6$GS7Q93|>sBS5E9EH$o zsUe9mj~#ksvet;pRFTp~Q6$#f2w{C0l}jP^WyDeEc~#QLsr-;cYlP4m!b5UUF~Abr z05`!DacZI)B>df648u?s(U#ZI6xWaT35^tBpH6^UC&>t-;l?BxewvDX-z;eeYmy}! zhtGmDVyIjpRL*i2GyW|Y4wX_`Vnv3i2z${asrFjgojV((05Whae$=W}Yc;X%-pXo& zheoXEC>4E78@5r|ascWa-8uo)12mQ;%k8qZ19)&^v0%Iydl+fi3q^}0xnclhP4we)86{epli*+&u&PAqHb5i?UWevB z;6WdIpc8_tby3XC1_QxV_t-U-^hR090ofTmM@rw?_e*)_99Hdrt$A*eTpbxQ${v0A z7_hMq(@q#GV$y-6^V;{Ak#ZT)({R1B7 z@%<7=lYSLiCxs+QuU!IN*<_#PuB%Ebd;*8o#KuYX^r8GLN*gZ<7 zRw}7eq@PD~#A4`h(?t?h?uETb=gEM$A^uHSA2L&;IJ-vr(!dYfJK#?B>|s8~M!D+U zY+Ep6Qopk|i6}?!X|NW7u0%&L)!-qC@FJ|glV52f;oQ82@;p$A`Q9vLHG}`KHO7T@ z5OFb^Een0o@X0n3B^a{oC)%y~iITlR`#BOw@)J#!;k^`AYnlX1U-u3yIg{JqEh8}4 z3$!LCB}B7{y)QvYn9KuH#SyWJz8T2k^^y)Hu^wnLf53cjDhFO{GQS%*f1(J3o}>nv zEGYjlu$Zbi_89kI?0IcIOrO4w%Sj{vL-y)JvOqYd!JZ}!HmGe__!TOU3;$hll@)W3 z!<;-WC*nvW-6giY6_dek%K@wN?bqE!UWtMa&REe@rkFh|v;BqviTT zi2`UE1!lzBpR8fFVrAp45`*LEFg*R2V5n?ePVFNw@DPa5I+6=Z#N$R~kkF>rl;z09 zpg0_(B|@~c8sKOrD~;Bb(zur;|u7$h<^O^b7sLL73ggr zEVix8$1T-dgI;xHqY8S1Tfn=8^AQZtgY5_$p=!Dp*gl-YW2_O$$MEk2w_y9A!M1Wf zqEFgZ6o?vBmZLffm>vT?kDbR<7oMJjXd8C~0xh-==At&+%1l&9eL#r;+lqx;#T**R zj)k}%T6JaO&C9#gs`I^B2Q6W;9}yVhD~hpg8I5=YrC8`w5ja7r1EZgY{_-2~#lA&1 zcx+=(^OvEo*2}T{=!CJ1PXGUS{r`AP8?P6%@d`5qg?goBF&387cIB_=$q)?(nhx>z zEaFjQ^w5Yoya3nWXhX=)gD}J)8loH>)&^04lFss|<@9s-A@*A2@Wt)$wh>D2(JJi} zH4TWrFN~je_2Q?d17||vx_JbhLHxM=_*omFXId9{c5Ip99mjk|pFatF2QuP&^SE-n zB(UW1D7e5ht!(g zK8M*?(}7sc9$!r_-Ko3_U)cCQQpEmUSR2y6`hdp*5m9=0AoNw9=>35?%47=_;p7&&-G=_ z!(tIRrjHc1z~}`>+cL9!ckAZ8d3;IzGV?f>hQGKfyaf+bJr#5EPP(4YzTP$8i}`y0 zI)7(@bZRY>UNM*SiY-p@isdJJ#VBFfr2fu1llXTv=V)=Vk2k#J&;*C)HwK=CfA^i= z{k!-(!IoaKWgwm;=cSVKIg)d$3|-T$`p7k`ug?Hk|z+x%~>?0?Ih%>9<=?cMyn zcA~%6q&vp)u)d6bB*&OX`#kif9x`&d(J{C}i(jfFPVwU&^t6xUj6hUQwknM97JN+dE;U2BPq6xUj6M#8m* z)PIt9?bT2XX}$Nhok`v`Q_Q}b{!RM+Ctv&D()WfGjZyIV|LgnzBz>RSdz(J@ ze|`V=*Y{t0SZaiuoL@8fc|E^)NS@b|IIZR{oY({XKiPRb`C8*i_mlLe+^5KIOVGo2j+kBAEhR*wi&6^Y9VMJQKjn6k6?sg54p`ZXgFfkWcX=xb zUh6=XZ}-FxwwpgT;XEZiA4T+)2mYwo#-XF%?kk%Xmk*JB-B)T5%dYE}*1NDt?1%w_ zr`{EfheqR}k$C9ocxX5tx`Gh?43&&keNP_cmpHFw7aHOoDp#FYRhZIlhens@Bbgpq zI_CR?;Y*@J3?V#f+I!6KCETZK95Qww9!-m1O^aVki(gNR-$;u;lN_g$88Q#6)ra+^ z_=JbgFMS^*_|aN)fLOZ^OCtw4=rj~|sqVc8>k%pJqPf7m=U@Xzd}RhWSq|>vh-&xa zONWDdID!?-gZs2l!@))lnaqmn-hQxIORhiY*Fswlc4(p6gFzYENu%swFGuKPJ{-@2 zc!*@fyod`_Q$m=9WeF0HY{l+BN{sMRNJat;ePk6ORy3e*AfxExRxAUp$rpX5y+>}h zjRXc}7>5E+-Y(pk#?yiGvv7*EZA84;D(=q5-TKcpUJhJ*uJM}fiMcgMMTffE>$~TowO2d+3VoEqZY*aACTN9CwGf z-Nq-;;H;NUfzwVxVCfFywZM~i%s{HMQ@APRMQTk@j0G-Dv5gR?FPiHK8n4d9qV)(B zxr##IB{y(hPrT&L^)wl;&BYV$esL|&ea={OE)Pp}o*v^hqh~nJ6B5pzJe8=@KN1C(4($eDBP{;Tjq;C;p`xo6Ck%5Pa{oSC2SdLKu#5P*q#8; zpzs>X0Be+x0292I8DM9o#MquGRu6&)s1=ZgUj?V4z%+36yb@ zxO1;N}w_0wt98*yOa<&>z2TE@Vk(hc^o3Th!~Q&$!Voa@-9ei-MEoJ+-Vm~cEtlqH~KSw*Vt34ki0 z9A+q!WfhGi#FaqI2Z(@=Ks<+zwLxx=C*#Vyh zE1ZKk&KXRoD1M6I9MymXjM&cS>9su$@Qg=j2tn#2cz^)afQ%53y#(YS0U1q|$6f+5 zA^_VpV@*?@yD6_`P&h-xUaz=pBp8Ev=#0x?jgX93#?Zwp3nYdR5@)}PlAx?F6~i82 zh&r4!Wuzuy*fRk`+Y?9!lkRi2QDB$n?#C}Aj6ihu;5P;yb@lEzcvett*^;kR zm@SprAn|q*!cKLC9y9|r2!peiU}O9M9LeEj8n=&Q?Ob9PQJrBbmB21c*kNTIsf1l5 zRR|9ec44d>6Ly1nHNAQ6LE#C~SdQj-&*I|#tWRAmS%prh5d;X8<8z3|$jO06_;i97TrGN9gT{qj%2Y8CEK+;;5xE zU%?PNN%*;=wsD%wovk=KR)xV0YS$El6ET#k10`$8I*@^bBGi;00~jUjfMP0oF&)@z ztT~id(@4O1!g(Ix2|+vr@Sp}E&;T|je^HXZgaR~c3NTwZTQ%%}obfcsF%BV(S{+V> z52=4a0R{=a5Xs*#{zBMn?#?`SD}FWkBQiixLkz)+0!!r_Wo5vK?|G0G^(0gUaoN1y-&03S(cKEiMaX{`BJ??DX`e2LMU(0q*~e1{lA zjNT3iAE6kV9*F`&>o)#dr>8mky36?Q5y zZ^U(9&!5$OJqg{HDttYf?rTiZeH{ti*TF-#CtdgTNc6HWx(Gb|gt@m^))ko=kTk62XcWQs&>}LA#4Jv7Ee&Am~W|E7}tJ{EPWm7@>~Ja za7|9K=rMjV(F;PUk?4`-mIPjizzY(gJ*@XqMK4I;g;?)l)B-;Ot)>Sm4=8E_7gH|u z6OePFBSR9rpeB0rp$!PVh0qVF=yec!jSQNK78t@9ddQ%5Z;)z}Mj`|;fnFz}*H7qm z;4e=c&3W!d{Kf}vh@@|8eBhQ^Di=AdCpB6+NcNiWR}hAcr1@wZ_Di)V zj}1(ob~}{{7frjX6%4YIXwKpeYtt^2V5>SyU8BeFikmH+FhUaVa2zGQR}0endEBc& z9*z-&&JaULwiONC`CtPEpcn!tsg{f6POa%ldV34S-`;u%Ktxew61y)10P$eWAkVs; zz>bG5LCTg3pyVMOiVxu)DTg6T4S~2a2l7i2n2Ui1=s*R57&H7*-h$6*LWrbP!|zY5?|LF$STyu{N7%oAWlxi!5KLGEn82!oG8$On>Kgp8Q0K#xF7er+?O#$K29|w@=yaNe9 z2e~!FF#ylS-JyD#*?dV_?Lzw88Yn~*N}q%&vze4S77c>H z(H+5GfkhEdN1o>peibY&bXtxGdE9KS*|N+G6e}^nERJer?F|dwj;~<)uyhfTAGAVn z#h8jcoF~CWlJs5W2?RRbP5C_8Azuz-Mi3b^f^Q(1jAwtk@qB~e^OFSwDLifjf>^k6 z50eoC(+uKyoMz%0zwsodKLvnfTF?>uLEJn`O|$wD{U@*1J{QZ2Ti>3Eh2k8v@6wB- zXu}|`6BLHP`5bZ7cn!8aa=3M!il&g+b#X2dkJ7|&CUE}6z|2J>W4dj0E@n~3#=ynt zwjtqq0ON_@wv@mhUuf(LJgFefco_v4b&IwjVPS5N3OWPlpF_1hfb40uvw@4#Z0P)6 zTOTAzIcDir9HpWH^jTbs6-N|f$l|&ohm-4L!j-8y9%K%PbTEL084@z$EEDNWe`}2X zVWPh^PJgCGKfrcWYV=oQK{B2GYNEeV(hp*Z`fK0=88k+1XPJ{qa6%kt^bZsLt&)C+ zZx?w+Ev{vXK{Z+kSap>ibER-)L$;;+M^u<&JpoR*Gh|PkLn*QVIw|AD#F1p?9I=qi z&rFAS+Rn_yDjB_RNKSx{r!$ok8oC5+QcqAj7SNB>SWlpo>+*%^OKnX*~Czc7uKz|vnWJ-fGv%Y9%3XcrOGNQifDZ2 zD~^qD30PbYNQec=v*3xHNJpSYN#I4V^vin^+$@1S8nbFomZ z-!~~25#$jUjj3Ejh>ONJ7Yk!tM1Y;fMOgJTrjKy84|^ujwMb2H5l+#y5$cOZ?h9yF zXkAAU>;MbEJwqR@H#G4G2ViP_BZ6Q$xlMjyMp~@RXk3t^NYxq)$_D4cM1eZLObz#8 z7z@{89^h-6z$oB2ja=gpQc+pz$S&nU&0ru~f*~GsXydzy;D{>SmSYOu5=Uu1cFo7l zpBBeL@X*lAJ+O@2IQ54pe4JWE``jiPbU2Wm)}kZPB4sAj3ECnnnO^r(hqSu3mB2h> z?1NE-0um7(5?U|dU6x9mrA&{XN5q3JtruFU7j8hDMtRPo>CSl$OPLmTC-uV(wV{>S zSgqFkC-5K~F2Zd!@xZnt=q5Jk4H4n}Q501Ypb&M3;J^DvBL$-_C6naBg? z9V&4anXq#t4;9I?oPh$7;M{@Z#Pf5~U#1zk${Y>U$<(VLh?1Aw`ssm=Gmorp!#kB)R@H zQGy`J8S)IR*7VUVfiBg|4~>gKbS+fRF#1%opwZvT^gC}5^%WKeUNL)MX<%s*l{q0q z@>7Fm8qEDXn9rpukY;N6TnsgT95ug&S~H<`4&DFY#zd>o*iXQo1#HIwg&fk&@gcp@ zC=J75X;5mSiFCli#@eW~{s0JTHnzt7JepnWEshO}I|SLWID^yyA*LU2aTlCp7FttT zxB(Ut9X}jrVK}wp!9ryc3)RE|lm{4)or+$FvrtJaRHt++5|g{NI;C4%sauC73mYwt z2NbM$G=#|rbV8?V_zyDi{z>rnr<-W#P>py$5l=H}O|NPH$!SO>U5c)S-4>&}S%3}$ zh=-vBVtS2a4r;1F5|1W`_?7-6|#i@rCp`#*U#!-5x!?e9NJyVEkoJn<1MGVjyP&B9{y8x6WL11{jn zD$B&}JGwG6uHMNi%f`Jsy0RQxx|4-Z3*Knem05A!PF7hy?%L6n72u+stg<<{Wk*+5 zge!Kk%8GHnj;?GzF4xH_TZj!QY5RB1O-bIr6GBWlv$b2O%)FcMWBItkUw&++PrpZy8ZX4)H20wG1k)*fNc4uoIGA4(vmwD9JnfLNVxwX_S= zrsPzt#v1==HucafAu_3t<}FQQNQ)uU?3ON=4{j7L4xcz~I`(5uEZNA5r0xhI%kOF)5->;%~?_aB+UHjK7Xy^VK1?|{hM}@M| z^5`2vhlt>)q5TbrYA&%N-PdQ(iLFZ==QVmo>LCYsd|wV6X`gc9?x%vQb4P<+xQVpj zD*M)gho%%96WGVTqBUI89?2CqX(M8}U97Qbcyr5YEVpMKCnY`u#&K|3@aXgcm}333 z3w2ZQP%?vTV%tYo%TqMR;YE;ZpTG>b*n3i6%ga|!F@s)&xm(e#qrE6ad@t6 zE_{?-qDP|!k*Dx3Y|sIx=$5VPW|TBll{)5*kfGIp-s~f+VPMrBacT|LX8S^8xs{NH z7*()+nnXH1*2s{U35?|tpoC8!PQ7E4a8aBDLouHlA8`Uz5KUEx$wyIkZEiOn8Ume~ z(?*Q@xPzE&!)!!2v9zm-poPXX7y=*&?ae$6-&w)n+^R65GEXP+c|iL;qZ5~mcQ_O_ z6c*h^l^MqwqE;R(Xgotrv{MrsuW1c-n8)DkUAfeshk*yR9#)ly#W8JoF0hpkp`CM2 zXPzR2WJZV+)Vg=r(UC#!MTKUdpnEQNVhdUW3_u31UIISUrgeiTbRT*m71NN!WM-C| z=)}3llbINXA2r^r7$4y@9zdI5>VgB&HZ?f4#t9cR!N+PfsU9r z6vKrzI-&cBHP&IG@mh?3-Lz9TqDk+o9fH8vax{7s$|P(K!WN#ZwkkuaWg*B4V?+Cg zfvPbQ!`4sO<||~Vkno*R_=X5yggCi3-n3lwShIbOsDd!l1{Ow!!qTrKGDLg?)g&za za}Ou8(KJ4in<|SDZ2Qa|DQEgaOd;zlAb|tpiH*DB=sa3ugwdJCG>9XZtt4Y8icPlcjBMFZa?2vdM;wey2_rb5 z@P(<*&JePlEd4yb@~P}I2AcMcT(DbViX>vf@PceXT}2TcXGGVGk3g%*RvnfoKx`vn zISkCeQw7o6p-}Z{4PJ#RWV|B>tX8P5B@eL(R24SVl~r`1s&gPW*gAtMk|W`qR?sE)Dzw+>@q4vAwZ3?wX^ zs;EahssTG*75{2;RVEnkAnbJ77!PO3%)d;OP53c&>S^jl$Iv6x50__ z9*?$HtMPJkWCa@GwreL)nui*Smo7^v+l6A{q+*nINtRoMA+3ro;G(2i`>Ciuwdip! znv75z2FJKuLoQ9I!$#>!W)rtG#-@I)K8aKP++379E&MJZs~SRnU}5&ITE!e<-3N(D zEEl43V67V#z(uVag{WJu8l|gM;b4a@knWM?4{P-%3PaEjqaRQfP?t7}oLU3WGL1$< zHL;WnX!Qf}J_(+mR&W}O`aMa6k!jv_x4 zlDNeAsg_Gd!&(iyQuM-BjDx6OD?sxXXuk*ki$v3^d`Z!&^(53x5s7bo2pG_cV}$#p zXz+q>S0LQrTSJW?3FW3U(_|;<)bb&ek*zo`x-l403d3g@v4+1+9B1m78dOUa41?Ef zA%ZX*ol*d6u$Rgd8vX|1i@@Cc^hlADme`;BYjlZSw*5ZKe0&0DDUPqPEeUIEOTrr4 zQk*N7%yfUe&(=}o;`0cK-13{E46ZwiAU{Jzj)In?_4S>W#Pv^+h1b`p3Cl8DY?&Qh zU$;^+I@#|Qtyp*4X?<;{^|k%2vGujq@k_#ueN`;Ljm55gMF<&pxdp!6;RUgK_87`K zM5A*dejcjkMe#c)Tohw1?$o-lbd?KZk3byNldv%E*FT#t7skI<3u82b7sj`KK(1_> zfF&(feeGL$ZF~o>jUVQytBILkv=us(Ls`WR%od3_9$d5P>osuOE6 z4-oO%wyD+QH@hxkkz5p8B)ejZWYF8v!i(hWk@~6lLbG=M1KU!oz$)1cpaxnRx6u(h z__A~J*h77_87T14V+m{Gx7NKHg!7u1SggL!#PXQvrseU;w9R9&<*~~$(eikiCB8hq z@c!}38$L)@&{tj`(n`jG3dQ9=shv$ z-2^Fwj4rUe+AofpR-hA8&ESbs?Q}~&|Ppc@wGn3(I{Je>u zHc?^^EYTUB!O!XZw2Kl)U`aN^H}f-#pAJ#t3@o{o;am9m5`H>GNlswNY{1-|fhDsz zdL}<}L`iO7$sC4X#?P1XGnX6!iC%!U;h;z};{ZQL%L>jSh~6Tgl7h{DYH!uSL&N#3?2q?D2Hk<@ts z=D^oPpNmV-g&!!a1@twcRA3#OsAc>QNH48QO9Q`^as!6}kSjZgm&pXT>@Tpald;5~==t{CT36u%lYKD1qX0 zUI1P<@q}6JF(g}>Wd!a~uu++1$z&R6xXiRNA=7GOue%!IcwUfHL?k7$!68}43eqy+ z{U5md_@<7j4n*RE6Zx^}CT@SS4trecFcPBt_evo$OX|nQlI7P{0a3|`s!tov3RolR zolT<`9)cWWApkkfM~5|AXW*_0dCf#6QXG~373Nx!*D^akJl%Y#?&Y`$-+?n5jrrLT zSm*bxA%p^xAZ8MqF+Ub%w$>31QF-2#B+omgJWG*vK%Vmf+QHGvBw_YSVfK#`=G!VJ z73Njrgn84%!n}4eVdj*H&hKgTP2BPHV zcJYsK!0ky8wEU#1azrDsp-^UDkdSW?$`vIGWQ9Hh;PcQ%cUJyhPjorl^z>nwm4 z5VWEaxZJYGqC>ji@{>FSwsPj!XU{wYc9Rga^AMO%C2{OfrnI7Jv^p{X5D4~!2aVMJ&_j0t~b#R|Se#b&;ehD2x6!F#{I3Y&;B5uaS>UV&jR7oum?9(tDb(6hXSo`0mrC^G+z4s!Nfq986md|#LVV0)H+Lrh;*BbUCa zJF0N#>Vv96-Sa1=(sK~^jm9yZ!~MA+hfDAgg$`NZpsMnO?x^R)5D}|qRWZT`!>H@Q z9Rxmu1DkPfAb~-gy+^-YIG2{mr3W3}SHF#J)1}aHZaP>%&F8Z(t$bQAzAE;E@=_O8 z0D!BD^sEMd>}<8k`=@EZgR7)<$9pi#ufwqfwK%)+6Arq9n!IXn#|GRdo%+shP2U;T zu+JGhtKnq+Zv6G^n~E+3(2l=TINY`mf4Ic%9zT8&zR-{E3-Otar-|@ch^k`FwDJ{z z2MI(XpPMcDh1?wk;e8T=tjbwb2dk4$b#EI+O-q`Rwic-9>Sh$NB659tyDFt(I^Hi)0($!pme6%G3J1^=`jDPtiZG&RwI= zLnAowu)A8HCtJdl>+{fT4m|GOz`wG23w<7a<15FY9Bnux@iVgl(GpO!Vy2tkO@ezH#D%?B^I?UD`g z=7Sd!W!FTlkF%$Z839pEWdx8h3zTFr8y2=l89`#7$_#yDE=kS$h28pRZU%JzJ^y$_ zp|-@4g;B*#V)~gfriGD5(VeTsxF(hoS42ltDu*OhUNPKsR@Yi9qSA=|@e|e80GkVI zlwcy!j@}{RT&;wYb3kBUsC=Ss*~WJ66@*n=JEZ8UUa9a4Gy=FZ*hG}6Q;DZ1p@Td` z2$Rh{#e^SFEZ)t(FuAEAwI8;S@PS+y3Xr8muwJ$!0oFoArMY*6d>D@X)x?w51gj`& zFNLLjIYCNViirFURB}HCYs; zP8R;?V609Zj7-W4V3TS*s^PXLP8NIq(PU8#1~Px*I?^ATEdDXCL^+Lz&20O#-&Nm4 z%XFOEy>U%?Y{s}ZU8+`yw<9`Z*wL6oq98pp5S>c~mNK+@;|!=D=eb*= z{5kh-%Z-dC#v?}+jVP{yE8}Vz0TUIgwhr?I@pm*W#@|b6H^yIP1u+;cBpy@yiMe2j zVzo@@kxibM=S(58Gw)L-=OV@)Wp7*n+qf~zUv5A1Rkkf_yE}A4qNZ=Wjd(wUc%Mu2 zu$7t{pDDdGDmzj}CAmQOJ-qh#$ejLx#E}^tkRTpJ9Z49Ocy$fUCYNfjl(-kV}(p+{iah`o( z+axpX_-H0ADSxv>R&ZIq8ktKHXDpK|`Yl#3u4WW889m|jmXHE1IF{K;U4~id;eLt$ zSyaCCNkRbMb5qDtnsPo{E+$kD`0CeD5K6>RDy*=c>MJznAu8@Z`wm-Y|0sT$Sv|4a>eBW5~67u#x zP--7ms1C}U^-dRytIFI)nR|W^%lsT=?vazxVU+R4YE7T8R?gUkT8m;ereD8Cf2>C9 z^=qt-)o8tbjWw|vZP%^wD>Ov7LK~M*m8uGZGG7l>8mrJTF)P0yN8=IHN#it$p^obk z`vn^3vFcsdr?({`Z<}kvdO6sJdV4r;Xe)vtuDb~NTjX75S>K|O*OuZBizt7Kz^>5S zZRB;)9X1jqQYoble!BSSRA8d&F zFaq^0NJN1AVMEA++37L*5eC8pe<(Rx1ttdsRRdLFaL7M-QQvuS+W#z%i^ z!y{s20Yvm*mhKslSDn=UW)2=h7G}Xme`m+z3dZz#TsVnJT9Foh86KDBu=vY}nG!xs z6GHl_qqEI{!4KPV_#uD5rNk z&2L=6p5ewc3ooJX@tfV(cw@Yvh4gT;zpgK7z17R>Eju~u*g8SL0caCLPTj!{eoS5~ zX&r_Y7eHIn*%sPF=xO@H27_L@Z_G_o-xcKYHw2%3R>!OyxuAcx4*)i2R&?;TG5xb# z(jQ5~4hnGCW4mUMfD^p*LzmDm+cRi^D08C`*kdDcesd4qP`a~I!-XuctJo5O2bGMO zLwctnxB0MJfSSGBs9eg79Gon-9gvGQB}{qGW_Q$pF?(c~tp~FW0pP@~dNF57<)5V; zSa}H3C;UR#a@@F%Rs#HzM|C<8zFisWHOt&J%az9nAkB=3>{yOq2iRp}zfzWD2ohQ; zp_L-SvUnRsv_(xKO6Xzx1Fn4LfaeMhtGxs6<<)n%h%cS=z_l;;-+`Tg1$R&=L=Q;6 zG}lO~gQV>L3VR)BWz5wyd50ldOu>UH$QB!CXy=%uO0wvAJd30^UXX)H1vv&S2~taf z01hvwcoR&Lt)w|6M%4vmI6^sT`uLO7GqAZ52{)1D=<)#wiU>Ifzva9jwa0 znA+Ys(eV_vz)(k~Ycwja(zxnF>|YUk91*AN^6H(7ob_c$eI9?$s>>01U`x1*$23oh zo^yatTS-r(M@KhZ_O#M%W6BZ+xJiV?MdZRc{0-cJp#W`a<*&DwCkX{&KKZ%c=$L*Wk zx`nv0m$g?@d%Aq1!;oQ83!_t5E&LizPCyV`*|8+x5)#-3k-p{WWC%o;ilkVPdnJ?y zvf>8`JXmO9!PRV2)kr9&Q=%Gz@;hSh2QVJIL{D8xDqQQ}T^PJ`pdr3Q5#0O{8?EJ) zj(0Q{r$_a2u?CUkgjkFfYsKW43@8+iAuh#Yr$A4{%q}K8x}bJg_QL>TJ;i;f_5{MT+;yotzIeU9LoS9nwMXua z${d~X?{lO*L$pWjKope$u201PO15Wu;zkYIKeR&p85o_zRVhEPi)jV{x`Rzfq_c%H zNRMafaSZtB_Y^%wWGf(&bizNi1ivmK9=~2{0Dg<8b@=rsl3C5gqpF>ar=Vh1Q8hD& z8>3V^)1~sr0J7D9I7p`?ns~&Gj=TS*Lf|dZYKX5N{-{-ei`Y$44M1*Y0H{`TR%}k{ z;kk-ur`T=? zeiNUxu&EoZE;>;?yv0yu#HKTcC1pB8X4bJOrYTo<5Gs^sHK|3z7M|KzpTfQ*og1@Idw8M)@LW`vLai!w zdY*^ZU&iZIDK2U4Q4Pytlb~i-vT&uH&^?1vzn(~Et&3ig!!AMVhNI#_C0GW?qz3z< zy*J3K4*08Fl$+Y$&ppPr07AcFZje;G1cib_C=slq88T#`GyH`z*oU`}qQ{E9m4 zSJ8bhHdPY)_IyI$Rxej320&IhseNlE^zDt9Ds9qKVN)cZN6N);vp+uhG?YzEo_o?C7Wc3Ii1Ghmt>M5`cGNZ z?@F2UvNguaH%5)1W>-yT)_6B{1`1b$QZ zd1-TWVlZ9sNUT$`!GfB}M-F&5h?1ToK7m zg&y8aFz|gi0cB1~<%B+E>2p>C3}g#)AK9`oX9jy59%d`ZT>fX0*$|@0Fse4+!eRDE z;C)C0;vNas%axb;jf<#9!bMAu%9ux@3=mJ)JZbr9(!!5eDRmWn#gVvt07Ft-5j#>{ z5o~86Ar!xlGsz#JlRrXF_DAUCkI)nS5iq%8vmuC2bVKY`8Vt=%c1LVTaYvwziF^_M zWM9OF8}dc$xG`VEwuvYB(EpMzVle89IFaa!AlnM#JJB%1-$fRUs1e3;w6I6tm`6%> zI;W8vBA49|5Knd!v*DhIQLIG9|oiBX5Oco!3lc%QdDmbrt0l5 zcLB|AyW-A=uK{Gvmph@>;nx%wo6c^40|Fn5vEj5xnIwnwjrrE-z<&jxq%qIkNv2S2 z!1D|9C>R^g7~X2UZ{=}Axd5f=gl#Hsi@e_`dHff8G2jd1;~(qQ^@TM43n^qyKK`$% zVf{F0Nf`gXy0P&ut^9bY8yNp`dC?bNKVY!OhgKE9?bae5yW8%eIOX~RVn`qV6 z0oj{q{2yb19KT>=1&}0%82XdTq7=heUmPR8*XWMA!fIx`?s&M+&)la+gl&tsz(SJ8 z85)i|3rTGpr*}816IXA?xZwbLxzUR6Ma*|*&+nNBWVO}AdZa_~<$lB^bW5w8ohU6{ z3HRuU)t2WlcHQmeA5~q7yhngf5i5+_6MptatQ|M@yG}Oi| z*0_T+xH)JDb#D{AXKB}6yQMCl=Lt8l;v-7hcqx{z?jc zko9>%3m?TJx}neWwJv2`yTsA#PEzgAKzHD$*7eYIs3q6JMkkpOwOP*pG=aES)$(1^>VSaQa~vs%pW6KL@tz^yimG=g;FaolydOrjV+R1t0s;XIdRP4 zMN%hQXU-BiaU6-h5sH?JZeAzFjek%Fw*2J=R!Hb*Y5f12S4cN7Z}61CbH^Zy(j@an z9rf~$c!fku@ST9rS?Y6LvWRmQ4(c0UDyNo4bS)Z20Up*WN3bD3+zsQ=T25lmm{ z6rhDsi!}PX@srnzMUnOP+c!DG2uUhFgKLcGECGrWfSWV(F0+1SoYjrh#HCuXvL7ZA_IgGtV=#ls&E2*X|BxZq7Jqt8Sc>=s1Hd@n)5MU!Fsx&YBoQ1(5wH;V`+k5S4t8(#$($OSjy0yqixk_gII-OO+G z^OMru^dEwRLy(aKTYn3Az&b@^+Tm6>L?#rz` zjzlMXMKrYKM@mqO3;88jG;8DhG5Ohb-05-cRm$mc%bVEg@$dUyFyq3De7`R0FYzRu z&*x5Oe@Qc3tMY>^r~DwxAwS5nqviCGIEc@eu`Y@=@9qN?t!P$shuCjEe43*CXRKI`=OGWM7>b&q-NpoPW&x1 ze=)$FP|cmNfC+u0A~c!4!X)|@#OU+H=yOQ=oGdT=8j!sb9F?*820Y*_GqV#(UBIN4 z5~*dmbVNs&92uU?hcGh6Xk>JRv%Aih($+D!?Dd0chZt^N%A=#5h6bGg(u!yodGq`$ zD(;Ck&QeUroSNH*V)JN#+VjrKQ z!CsL@Uo$(AR;a$eUNG+a^TO+Wf9{Qbf9^{7oEtc7>L3SWFaPjq1^DjUpZwi7X|sba zY;$ZrkQP5%VUOI%$z>`l*I7vTKo8K!uJMlbNSIDHNT{unv94vTvG3{E18dDh#~*k} zxr{shz`K9^_fGk#-#a}V*V(17P&)fP3&zI&HQzhgMqkYLPJbv!{N8D8lDym>mlrDp zgijArCwB1QlcHjeib^iH=uH(Bw>qnUkH?wxtO8G5R#NpDnkyRJD8<^unb04@&k*C+ zr8WIguUuP`eCPnU2noUP79CA3Z-oc2;Me-@&MCojQ}TNDS%6`7kd}bx1^$57qHnxa zzL$sC&)Naj;yVw>lm#FSewL;D3i}~;)1r(G0M4>>kyGA9XuwJ4ywS&M`zt4 zI(S`KC)bq?FO{MKt9Nb%EkCEdF24MXXIr7N$%8ZA1hxIp>uK+O1&=S!3N<6tMLDhx zhQUx)BI!^Sn6G}F6v=<9z5AsXdp^d$O+JgP|8fBp?I~(%@>5^D*E#j2W};JHT&%D7 z2g2%}{L~jnJsEg1yEpOF7u2$7+^H|6|KQY@$>e)wOQL)$>Ao}hAQpUR3n{*twty<` zsWgl8Clchqte7B+_Q_|M+P6KFf!U>YF`9^D(HGWckjO6}k!Oi_$4`FBMcXP_;vZ#+ z&s7rtGKI-3%pV*3H_N;4pOE)&HozE#Vt7SI20?3QPH~v;%N!fycu{IYO;g8?A;jH9 z6x-M3P=o7j>(XdSs4#DV>!qW_l_pOVYcFwG&^EEuVU)PVQm0Yk0ZXt2UXs6N0{qJI z=gLsMdB~2+ma57e?Mt~bI&EpGn@(CCB{vS6S0jJX zKRX1lqWKY5SRlbrmwd{KWy>k zV<-e97KN;0ou!gha`LfGDwR@LX(eK%t%8I2;8JE0U=AEkESCXGbFqaslX(HwD%FTm zBJ_S^f}whZ4AsmgI9}8BjlV=dq6gzE)}^!N!1T#$&=pLOTBzjGUn(2WO{rW+HB0@{ zES<#SOm1DNfTfE4{B`V{gKI^;UA>kIa!3|ipG?Cl%n%ydO;W?1JIR_V_53bigfLsY zB=W`hc_n_*y(I9(nwR9g*y<&5FV66iv=>kDlCT#~^_F1p>iQE)EyV#nc+RGE0!|Oy zZDBZYcRGI4?$$2*^3&^I)qbb@Rw(o>)>{{ES?0cVT4w;yrYqLkKhwCmwew1j2EPdm8a=QdC(8gKQug6f@ zMT7EZT5M46(rCPux>l@<_8_529hfPHuT6ZC;`sB|;LMX|u7@p={K+hlRTGZSht>G} zA#4dS`%Vl{sssYT^Qkw$^hU`}9jRNS4#W5epcjSIz(x8KX((3B#rP+6?L`$+57Tea zxDkNi9wU0~IHJj5uai~RNh_!!HX5W3X-NI!wP8X}tV|k3 zyr4)mh?M!nItLsm(%J!HHiU@Z67!eyAajy(!Z5R2iVC_Q0+`Q`XBq&?OZ%TEX*k>> zheQ2qqu->LCL@fRPTQsFRF!;Ju#glO#a4A@&J0Q-TPc0tQ1$C{LuZb0$e|eCO8EYVUDP=BPjef8n;IQ_ zd}jSt;h?Kx%MT!zQI0(OC{K9=H@yo#f`Io3Kk}GH`QyUxq>J{-9~J%_QIu==LWXaf zm}>aW7{1+Nsnzfe8NOX&sf{jw@$D2#Q9;-!-!6`es$Ro4VEA?j-w_efKes1(oKH{b zF|)`3hUAFWPNek#LXA~JvQ!%i$r52oXjOFe3*7u*&5Gj*imHRM zMA;dIDk7WH$c^n#10?J6uXEr-wvY~tMFd1vDia|`yMxn z^NAwgqeiipNbzkqiWd;!zHLS^-sIhSpVq#{C|<-zwMWMTU-n{Khu4bn-(jBSkDTpv zK6_HSU8O%cNxDs?e`Q>{&)GEKy|-Ca!b=;-kEO(V^2!vMlfy?hx#Kl0MGvwT~yC`IOwDCJEpj4-Uo8y&(SYOJDx zYSOCu3vf2S1Fzqd*$W`sLA!PeN8nct;0WfSm78?yqa7CowmU=_Zp#d| zO*QBa6qAY^Lt=RZ7XSv^ZQ2Q=zE{)_(XslYz=^Z?J5a=lYYSRY#92^whKdX#v3>|H zf?$VD8#WptreO_N=y!ld9MIo_A`Y!H*p4C&T=+vpMv&MT#_QL?7Mm79L+B=t0o+y5 zF|{CwkqRWi78D{RbQgrAtkoz-KRBrj6qJ*1iUIjVO9a|Sl=oAVLovZYSMWt7foMns z-f?2XMWfzPAg@Mel7{G#&iY=8vV$YqQDPtNPZ^SQqCG=c3lld+jYd1s8P*PiPACV_ z*i$gVgiilMXx(RfZ6Bo7MMhzl;6$T=bhNwgz zmvEwlC_$<5**R`^q1VkCb ztX>Stk|}_+jFnhVv$a5JJm}c@qReEi#5xbdgE66i()nRhC>^OP-wA$^mOH~3IDjz~ zQ<1*@n9gJPCLm$G7sY_erQVd%N$PmMuV1!=^gjs5jw5PI#6nt}n?a3ikE`zaadv?) zI~U;q1W+jDiZ;gD5=x!Eh7y(W5T-M3PSbjF<4(LPBi1&8gs=fICwh; z>dHCWD>?Al3J&D3{Ro2-^|8U(KSi2Kh#`FPr1}mOnM}_PEs>tb5fbHeB2oxdMz5$e zyI)Rt^v&->B+^X$nCDk=+@=)>fKYk7v-usBb0GrJxS-1UDg^kz{5#Tj{oy{B6HXwAMld=c-lQ=X&a)TNETgycEfehR!nei*bca7ch#PAdc{?1FI zlQ{63%MPq7g0HdJcfem^KF)T=HTXFTo?c^qa3XwE`$T&L#gn2~=c*X%+3>)eIZX#? zO6dGEtM{L``!b=!@h)A_mh#ML#{%V<)H4_KCw!U85%K6m`vWUr2T_-c6Xshw;h*r0 z#cCO&TE?QajFko>bn4x3UwosZoDR1q*GQaY5LUVG?K?n^gY-B;k6wB_PLG}R*iDbU zxI|?eJVWXRR-EhJkC+{Z0XP6@*RwW1j3qjWdO-`~w$fKDiTAT^&EWJWR%RT?J4V4q z1oMvTPpr=PMSvntQRE|t#I4dzf3W18ro2xDkSz0mijvOTnx3=BQojr!Iqy_7cK|U> zEmoPMDN6xY1V{LC06?K=Dcb2@y#A>xSv zzbIf<{fZt>Uxz^t7`{^h-*3TO;?cc|NinVswEGTNCSuori$U)_JSl_THyURU^CvKg z{Pfe~3_S+uF*GrIpb*i}1C?kqnREr0p}G)pWFl^CgQG6vfd0gG=81Mxf8ud&xz>d^ zW=sI-O7_tx-kjwZ|19FIqG;Fq! z7N|5IKm%C|*b1J$4;*;!-y{c=zHv4CLRi}R%^zWH3)qi+O4@aN2Fe5e^yK zIkudY+2s0*nTg&YF#$V>O~ebyog$YUZAD&^AM>Y&WQVbH8e}K-S%S}!`_uf^HQ9ie zeX%RaUfoIUEw?q>-R9Mcq<1-HxNmk#!I2{KeX4Mxed0;7Puwy4WJ7v_ee&ar(&{*x zmS~GSregP{CE6Wqygc<%p5p=Y9KSVP*&UyG$)tA2;jAsZ8pEq5ZkUw*;r1GaBi9dB3bA=d0j3ee?c59gm!YW+K zkTZWm!R@FwZl^wVnW8v3%Do?69>=w{vnS@7H=E-(QKQM~Kz=@_uHnqz#?bg`id=-q zeu{iAB9VEk%DfiwHmdyXGIJ3{=JGXIWIrPkiXhIZ@9?N%lQa7M&q%_o^TO?!-ap-# zJ+n2*p80Ad73sOWVcNcnhku(AJ|9UAUmZyfFT}oKD*d^*CGuYJPVDsY{i$WP;ZwK{ zx3ZwbIyWdjkpsszE|4rJu@$Uw&J7kkk~8-dJbQCTaCT=wiG6Mm?iF~0;NiyAk_C8= zpf(r9?r|C9n7w9{*$QfM3;eFRgYcxxrOR7IT7fp#XPd9V2QYt$70dkjOKk8}%wGb( zi8+4>xx)+I?#8X4bIWY=8*=8?{FaH5CXad|fd$blfEzlbB z0KF5$_mWTQow-I;r+BB!s5$`m3oddOcflyTz1cb&KKl>)I&b@6ReyG+_=Hv5<2HOP zM)~e$=Nmrg+kKl+9%^>J6}txpZiYUDOXWXUb|4!*{}1{GZZjIU8C6?xmHhC7@b1G4 zZj|>7Ke)>R(ASbha4*3@1`mp|9!@!v-Gv&5|3rcI?5^Rzz?Y|m;aJY@(svG8jIti> za|`)RU>}2f0h;jh zkT;Z^JlU-{i@}0+P~Y^>{RD*w+Dp(8g0=xdt*1qK zr@r%&MZ2ukKWfx(%RVJ>*l%t+2^t;`TJl-;@#@TG>rG%Gdc~;P1U6n|a&~K-#F5S@OBD+b5Ok24Nl+gkQzhy< zk3zJy!{U@t7RVls$s6h-fs+h7A{$CvImknXpk6?dkGlY&p^+HFt{RQIvX6@4Pq!1z z+^(ZDu@|0=cCDx|ul*D&PKbBoPIC_E^CoeP=7)>F;5AkExq8D5gCo!ohPh1yt{8Xbu}*Z$xxa`eVVfw#?I+VI)vALWs3ImKn}GofwtI zG3GAp4{MYcdsNw{v1N_j6Xd^14x7g?XauFAsTez$GHk&MX#EjctBvaDqF7{+QByez zLBwVR&t@P>*DhhxBD>qDr!C=l#hBkvx5{gy`ehX}PzA6cUe=AB51BAMq3-nH*>ptR zLUj*N-7TWAKe6ru6W0Bbadr301ZT76GJbSGNR)>Y3)w|^3l%yrX(3?h$27o&v|}8FcOLgqp}q0J z|HqlB<*>($UBW%AeXxUa7~m`m8W?G@8tGkvf%+bHkj5fL2rcWGZ*}n!&s|^ZlbRG#_nWbG3*tqNrj?Tp0 z>{n^WuPPE8n}vZ^fEg&<0%r1S^95j@yj)@SnGS9zZRvuuG93;jB46g4mbR8qM)1l@ru77tPXV<8 zeWwLVrqOR^pd^#3pAx*9J*_WLaTA1^>P-)nOsC&zfsz@)k(&d{b zu(3~cTZ1Dnk#t)FC9~+)9w?a|SUwY`t)%XX6XhjcFJ-!jsEXV`$;$%E=SVqM>xErO z{xG}|J|ZqQH?M|Q$y^j19c%s)fz4&R&DT<>e7EQ_-2~w^pA&x3X-+-C3u}aBR?&s; zPk+O4(Xzef#TF{ji{gHi@0H02QQ8TlJ!J(I+nURJk=l-M(_bw0gQ(JvDB$>ZQi1PK zftyf3=Kpd+e#8)hkIMWAHJ5EN>nVRW=ih|H2jcmA{fI*SOJezvUc%MK>3PF=da{$~ zc?lJmAERf=czT}eO{C}fUn2i|WAvOrFom9<^(N5s1ZAHer{}u}r_j?R^UL1(4ALb( zW%y&U{F}Ldy8VbZ{V2j~Yb$vP&9|HzzoM7p?cum^VC0>GB;cho^W~^iHUAcXk}^9W zG(wytxwvqgX_CE8Lh<|K2}C~o6tc$XZ#$mI&%e`l{Q*^7bsT&sC~UyMVuO-xR5Yn5 ztz20H1!Yb0O@6M)va%wxvVx-0MhWXZuCJ(YX+gP0o0XLnIJT*Qnli^GPIGLtjcvB> zCN)$x(V6u5{yZqthU6b@V@`zKPKkRb( z!+zX)^tn^`)&9HO{%||)J^FlJ_|^WP%hhUJRng^x=8fP`^YbS0d;c8G{v~+%1REi= zJf4E(<=G)xcrA!S8l=me*bKpD2VM4J*8ypfF86WHJVBS(XGq5;2zE}419Z=?7h^-j zz`Hzfl|3k{8OHvzaedC&CxXSu08}!-dnm^ZEQEbnu?1;kWF$x%BW7@65@inF7%^&w zgZ}JLMNbeLDg8mb*3ys>T$5$a`76K98DW2fUfwburzlqzD$B(Scji6!UL;=Jtv`@! z94a#x-FI;U+M&#VT8Aq`*Za+@4hx`*a*anZfXvHqPp|VWY@pK0hV=&;sQ8sZW%FYj zBUI+6N1}h$veH50SfzPAS~K>CZpkI_{h>AfGVB!|6%~wQ#)D<%8&sc)LF3^n^K$#{ zP?h;}+}Zt-{-nS@Sf`$v^GK_)r{!Ru>1%vCz9nwnBW6x)Ant7ozIL9T#;tw!KK?5G z!?TaUl08&JFJu;vH(nc4x8`?5^Boq}bvL)fy{)OYt~7b~ka6h9vv8B--B{>nU2ZbN#Fk1Skzg( zVEx3juXbQcfQ(s)Ul)cNXg<05D~L(Y#zCYOtLiBtUZmtU-Z*+ zt!bons4DlsqPQ5kDs98_g9QA`Fux8P*2c`7ni8sL3x!rwGW*~mwgU=`gO%oodM-+a zA{rHJzsFG!3KenwgOpG+7i^>g8oC)Oh6}Jcni1wf*u(w!!y5M5#8XVUryFzI`3dkA zg?R@&ygT(il*KIO&U@|lv$Xw9;W~a4vaV|ZjoAwQrQ9kmN3q`=+M)dd7gF(Y^B(*z z=Kkh0xQm(dKnq{YD7xf$VSq2!pUeK-3&}e=aE(Su#0}V!?R$kDx0!40s`QLLrX|F+ z@er#Zz?bXCxpp_#4vpde_ZyG)T}-GgxMC_k!5V8m{*ax`zL$mkd`>8LW!||a| zCyLJwfg{+w50`*taU9}7b3ffIPN2&HzD%OaLB33(%cFdmPM1S`nL(Gw`7(G}f4qciA-A`V^y*SuLYBhOB$*klZ&7=!n9KbW^IsG@nT2DSd!MZQb4J~be0nJMu zvSMiB8AQ?0q6q}jm!9@KZ>)3sv+3Yd++at#_)+VNxc|KRwRp4owee`! zt$%*cB)1L>INiFX+vC=cbxn5bkKQxctqWBQ7a%_rhIx!5e%xQF^kRC0`$4~%D))3_ z{^6{;wer67pquwk4?5lYi20`-lij)xJZ|^xVfVe)(!WRDcl-?bVCICnFD}%5`BL4N zuk|&AFFA)wE7|+^zg3xZM~{y?9Wr}cLUf@{%`(R)$xP>GLpRIgN#C$ooSmEj89S)p zghIpAU=idSZ1I+oSuN~}z0b$z#J;O9x%m#V@IrEOW-u1AlPB>dJ9z?MrWiM~bI0NC z>=Q;ac}=h*hG^nJetMVq?Bm9o?6XhdvBKFWjhM5Kp@vTyrVPqbDT%U7%A*iR7bzmo zV0p-*#!&DpS>&8$8NttI2XDx!3f<5E!(|<`Ck=CYY1$C~l=S@{kottnHA}DnR(&YkW@S_skAy*v*~Tzpk~v@e(lVr58}?wrZr%6 z&Jy(bkLr)rwAF<+sfP4}f->`U)PWnyQ9@IYvTEb=%Z;zBFbZmon^)2{A0@WY+LX)T z4TY=eNl@V$+Ab)p!<5MAL)VQ0f3VOG&9UeUmXsU)G{q^br76yh)z}>k7Otj=PT?9% zbVAD-f}dR;{L+fxO)GfSd>e|mc9dv@`(8I5K8l}+KcCZF#nWZ+!b6igl!pI_>*@$ zfj=wgNc9@y%=(vO-{1GwS(WBzu;~hB%x|cF*XLH6HCBnAOYng71}ecj`LED;Iy(i$ zOZ#4&h52ZenXk;ZZ$bMap~}p(3j3`>ye~4%DjcP5yn^EOXMH56$~^guk}_g#A;+x3 zf>>KfpH)~J8x|5LLhiCitqvjIwhDV3Le^S^!?uvABIH9BDPf8&WQkRnKgAaEPOGqb zN?6D=5t3z*8XZF7t-`GiA*Y{4q1271y38;LhAQ(>kob1oA!H8<>H79;c>`d4{Q;Wb z{oLX$@qzbD0$6V7J2|V&{EkIf<5MAsE9)#Fn@~tDxf%r;DGPH$H{}NT1tVk&jA|qb zjB4ZvjB2C@8r2KaX;d%Fpi#Xri$?XrY#P-Ib7)k@(x5Jkqd{GmK!dt4i3W9H3JvPQ zbQ;u!88oO1vuIEkX49Z9%%MRYPYbsJOd-)aPslL3c{Yae%~LUqaGr-@jLRgfc$jBk z80RwmDmHoUg|RLZFM7s@&F9fdGcYWjuIMx#tTexD-3=IrD$Uh$_d(Zw)%O3>cs#Jk zPdwKQ9avOOJSeM{p;;>fwIMn6wt#&8|F%u|>lmwhpYo2?Uq9s?t3R?z8n~pP(hNNn zarE+ttujCJly|Jc&pu!kj!Iz_CC}ogyrY!HKMHk}dPnt4i&X0vkTFkrN2wp<|4HvC zh2&#a;qauPem_W)M(JHBoHR z4pxO6tO_|;6>_jD^V6~8g z)j|$d3mw5KTA0F`7FzwM!Rm=87(9uD)==M%LOX)>;LeUHuCyZx9Ehu-J+n|JKiZ3L3qwmahP)4JW0cb`77+qwJn;9U`RpDOQm%$I+9mvg@S zZjkKxatJifd>QdLYr1>Ch9>ooRfR(17ioo(g0-PpPCrgkk%Y3p;cgM#9mCByZh~WS zQ%yJXU!sNNATF_Bqmoc4gX(wgl1?;lrLv8UOep}xZw4*WAd|K-sg_Bfwn)sc@>-cx zW|793M2(ONykBy1LIpZ%^>D4%L{ejzNmC-Jk-!4~yfcCt`AixBNfx)P0R2>!*>Hw1 zpi93~F|)v_m*1(F*}OBVUaNLS)oW>Vz2>_0ns*+J44)>waOu%&>kCow`pf-M^?Ky~ zsCwOVe^kBNm85zNkzOUN*U%)rQljfs5nZo$Mb~RqbiLx-dNsU)_P3uRy>RK#tKs>m zdhNO|s$M_7FREVOxG$<+tM7B^m2m;>XRuzl^yoEgM%C+e(e;`UU9T7KjjGqtdtG|< zkY0_Wq!%tddX+@iD|ByEy*_tuRK2RA>owo4S2aZ|6Z>+QYKA_ao1E$kcBg~#y9u5i zE==KXS1rtznWxS>t-ZPf3;kTWP$!cMtMRY4aqZNzG4-El+&T3u?V{FKq2T41`lTp% znG1?h@KQ|uwJ3Or3*Lf)v6%X+Q82~@m#;VD*1s6{rLOP>)Yl)9O_=pB`c6(;|KgOB zu}kq$*1+c};~!BNKYQmzj&6iO&m-w4G zJ_?q~yHPJ|&M99>_~8fvmZt#Jg!E$#0?${=df6UpD)4A3IQy3O}Q zwfR@?iE8tY+!NL2B_LrDA?au{m}c)0`ya-~8t{(TR9~N^{4Q)hJpX;NX7GDa)H}Z; zs(MfDh^pSc9Z}W$=?+#8)XfgXk{bJ-o+{aEc38b1$~R01M>y_300me)qt^0m>m z^hMIr=|6}*vRU2cSlw4``uC1yR|#2dMiOv^>&jk zq~owl$7X66Kg2fsl!fM&4)#=`Fgtra$HO09)Xhq(nXO#@w=ULzHRjFt5iMxWC$35! za2)@va?;!wG5Gi?9g zsPt`2YGP6jH~fr}wAMBzEn(6Di`3*0SjVJoLV}`a_<0)XR82amk~?X%#J@mF&J`0< z2^0mp`58-Yl8{a?sfkGC7HKXwnZ!+Q<33z#k(gcO9c9vMg#;B@n>NbY2Tf`mmx53h zDRjH++Mt+4po~;KO(LH7wMt*jq#`DrU{bG=wAN}SC2_+)u}DP@fpeMEA|xn!nhPmo zzk_sA$mofs`6pI#43~g`N}wp%%~DJ5z{^yllPN{4&D$)}7?TE=w3OPSnQY5axJaKzgqmm*5EgEYw#PiH5fj>UNp5Uw2`8kA4n6T*ILUsx-%XH1Vl7H z{6{U`aGoGTAqBc~M7sNz7Me_&&!l}!+Mpz@1qO3y9ZT z&IKb}KqAchA0$6u;Z{v*&;0J~l1#Mq6za(=s@%-#OVi5xaph$aQ+SFuY8B7tViI9> z{trsh9&XSYyHOkklkfgw5+;5D#ccRRR7`3>@?vt+CJ!bhn>?7@eK0a6w{Dz_N#dr+ zn3Qddh{^GdQ8DS;7!i}7ZH$V^t=ppd$;xd}F}Z%*WK4>`=fPy|_dJ+<_kqZme6npa zCTDMtjLCIv5i#j+i;BrF+9G0dds|dYKKb*gnD~Dl6_dAvdd~{aw(e7ByNB@&dw4>{iVJ%!weyuk4{MG*S8a-IH4l^;2KW*1J6oheo-)LCZIi z0F_<$9U80sTtK|$N4Q{=3QAke-|wT5%VMo+)RNipEg3}GZVYMkMylD&I7z$8`&s2> z5>t2_p4VbUB1U!M{Q!{czE!jm`-5Dj$SVxQd*@wIaR}TM8HY6}_u{bn+a4TlMuCmP zuDy|Q*!a!KI9&Pd$T)oBn-Ot1{mrO2JPMK*hrQp7jKdFp5*3HWpG3x?7UfE-jKhaQ5pj4S6cvXy9pgV8o<5rdt{n7e)9pA zan7fY>(eE=dGc}I>yV_25<;G4jEgL7wsHz-WJ&?g1ZG>LK_-ELJcdar7K!;)UMrJc z`mvJ6nM94S3Lt&?u(g}*sMW)@e)r=DY78@}6QoIMB(T6BNR!maXVRxZlHF`pU=!^g zT=5uTK$m`}V&*f0QT2L*Q!l?$F*7N;UZ?Jes@E|ksb2GFAK~jmq!%tddc7~YUf;SS zDqeMWMAhr2=z6`^t=ACg^}?h4bZL@azd00Dud`dC>UDfeRK5DPMAhrAEiSzpXjfqw z>xD~?UROld>x0qtDvGYx8>8!WsavlM3WxU{BfW6x(d+9EN7d`VkD}_e?MG4d`u2~a z>h%RBsa`##*Hx?+E`(aeQo>Y?RRZVH46 zW__~%U_7ebd=|~L+!nz5$xXe<-|PU%69`Eq^F2R|+T*K!7`4ao(R)17LHq99E(c`$ z`N}!Z^A%>V8Nj1~AM*2+A4E~{`yEkLytN~$iYq&!s(8JvV)*IBIoC55u+0vu_^u}% z{$d+dVpI0zA_0QAiWu{Zfw8T*<-fE;_Q`kA6KV`-R`Xh;^OcG)`gN zCGWzn`v&GFmAP23PSAcZ-_g2}=O=X63`Smo@+r*?=8|S>`N>m|4KxMGwNwQYEy$R) z3;9pW@p1Trd?dlV_yhHCt{vi|73XiGX6O=(^q&9qO**6LQu#wtfIE7-|B8L|CVrZ{ ziQn21N|RUdj~4`RX}^k(Yr=*;5jf`|9MHJM{Oa~->$^es_udX8;}8J7yq8Ru)b5Y> zQoHYzcEjKMYYCx5+sCEdKCWHun-jl^WFMM~?4Ck`s%C{2XTAJL<1@F;KHF0Aw@|_P zt4iXoDoMDiWa?EV@mG~hd-?E;!=a>U_&K)W?DnJsT)J)l&L$p!9T0 z=}UpqGqS!-n%2^@0`IB6?c9u4S~fM()nkEmFV3hr6R3GUP;;hb(-tn9QFA&_^FpBJ zbjzk*EjSgZIT@%q)v{?=3q}JqBY~RHmQ68NaKRq~HGgS2*|I4cw*|O=JW%u3mLn}s ztskHDx!YQ@@GBPEiPZS)t;stcoO3F92R=s8N_7)){owoO;A42De@Q%y>-Qy|28r6? z!VyPduT^-`QMkn_e8EvjolD-)xWb}6&$Kyx?@QisDDiY+ADMH`Ly7wV_ARjJ&1T*& zW1@ZEmVW*OIG@Ikan$m+OK+Ki@1NqsAiXE?J&9?_od;9!;g1yl3`p$euVIxvD~3Lu zfnO6jN}oP{fWM$Iy@~HoI4>5qc>mOvz8qijj^54utGRm&eAFwsb1(sSIgk_A_e??% zMVqG+6=jKD4qsFbA93_O**2;yoQqjrKhjY7+NTdd+E~&lJ@sM?|G>hV66M+weqN#=+$!`pz0YA#g%8;Uv9zOt2X1iE$Vr&tX3VDs#oOrP%|4f z9Z+2EX*`4Oamy%Bd%fmV6sa;kmDny4vvO{Q#IYEc#7vLGD|*c-C}J!U5B5DfjU}WA z7PF``>9JufUQ3mkErBb)#v?3Cyk;{wP~t(~6D%u+#?n%DO=A@D;#hV(zFXRP8rVFS zk~oTAjKQdU&WR1aGy}KDYWd*QAbu1On|{wv&GGe~oWfnf$5Qt5*ud9G#J~zeJH|!HipAx_m518b~Ls>Q)s81!NgNi|i3w%Qc|AWHAjVXJT03I4;_&}ly z=*83B*ep))+{Xhe!ilN?DJr@o@gVx#09iC;%!zfo^x`B(ZTAp^3N*fYP4^JvUu^>s zLkzf=$GY@$k1{k)V{FhA0r4teLktVR@PcA>j@qf7+9{slv!dBr)zvIjy%4GrJjth6K*42?om6#b02wpnIcif*N9tU zrbmKfd|_~H=CWCd2PfnwZ#U!b5CmAmjHs{G@#hVzi`}CQ?Hl+Z!AY^Y3bOW5_*$Nm zQwC8xacz!$EH(yBjDzeo<9s9tI2j@+RsP;BPwkD2`N?fn|VXYzKp? z9oxhns>-Lfp+UaWUmDLgn}jz{d8N2c8LOxn^FzYom!I6KRmo^<6Sry>+A7C_uKK2e z?rAFnjNn)aQmd5Zkp5uVBAiX6{ppX2_O`eom$;R&{AUIJnEQn{$L1YY-mvy}3XA?= z*j()^a`_6Vej5?B_aJiDL2)Ym5n=Hwi)uz(9=+csjQPsQFbJbZ=~OV1YT9DDvb3=* z9z5n>!LKc;tRa=9UC}@0?}c$ZCd`O&eTpj?f6~;VeR50gzdY>j-ep}o;73aa=g^xJ#%(wBJ@4=w&BZ8+knyxGX z=|Hu4hX|Ty3mUQonYdJd%m!ghu^BT|H373)=>y zHEMHZDVGP#kqn$QH#+H?!jRM%qRz$Lt2h_iOFp9Bijk=t*u+&Oes!c4_ z_d%znR)*olr5o2x!Z>O(W+|f+*Uy0qNn`3F}JIHfh{^3|13dYWy<#IP9v*sd9hWCNn*udO6czpe6 zvc#^Iw#O$wU>w{a6=m6-w%>pjU+ZJN_!m^6DtAV{ra7~cwCpoy2DvuzG!TMiH#;Zj zovsObKmI_c{F^mG3Y~)_h@RQ-3~;H6%BVe4UeAQ!i4Sl`wW!4E=sw%~xubQs&?RnK zQ_h-L{w3Vi(3C_WW!0+yt4@{&2IDiw#?nH3nCPhhQ46zJPX8oNojj~48cslKCClM?> ztqV4k%U~Cy0^=9Jhm&wgUt~@pf2!rrV?Q~w@0FQBGyoFCLDJ$DX&{Fe5uEOZW#+er ze7VGYFVQt3fo`XQHLmrKaOEkN=7BZd^-s0r0bABQmF0ov0b$HnMg~|IJ@9M+BRI;b z`yj6-pgkF3oyeMJ%NkNy&eT{1F1S-UM-X;E{3tp{5%#`^0qR_adoQ+kSJ3)Yu%$9! z3+NhbeCq_?R%-rYRXA$Wt`9@a`1%FkC##&9d%m5y{Z4#)z@=4{OXtjf55(UR#uA$` zPsMp4{+KZ4DWh7<@4>e~xcs)bc`D9>@~ee0-)8Jl1)V6Ls+19-Ev6IQlZqa$bee0v zZ7#nj9sQ(|EjEwCxms+AhIF-9ZrEZ)u-II$#j0(K>HbH6y0WA)oNa=#`p6KAWsAk~ zKvy?0c2d-LE{=#L8`|cYQ^95vvh6unw#Q`0E1VvXZF@kr$7H{)a5_P@?F88#tF;JY ziOra&5OMR-bV zo;()ivDin1El=6V^5AhB>pJ1_+oI;ND38H1ge~7@>tU@t<~p^E&6OTDmu0H+Y^qvC zF6|XqESu7nSWJ;5o9*OY+GZ<~P+LGse0Q1CZ0TXMd4OKM%xSiC?r8*|i-m1m*%)&# z&{u*7#1sZiiCL4U*XM6^+ALjdHVNw^!d7Cl-mxSSNbi&QX*Zp%d=SC;oxna1S0L9$s#5$LI8o?7E^E3YAQzg238~tkm{fSwL1W6=gGD?!|z0Xf75xTQe*v6HOdlsQP8<%o-=11xdOVoapz}C68c=Vu2GTBjbfCJP&o-95^ zJugBTgb%)>^Mh(D?Qf1mEqz_5U%v_vMoteXmD}G2v?i z>eF3A9;C@{ao~~F>6v}!Na7gL`um=nIs0MMEa0^w7a|_d&)gF$KOmM$Zd{&IC;q=` zV*Mi!a|~i$nTb#08xQyWd8V;v_MzICnBj@cy{JU%>1C-+>}i$exh1hYo5RDRC8-c2 zZf3NzLl|ca`FUxqn+<-xK@ZPnCT}}Cvu}82-^H26A^a@B{#6q!om66vt%P(^t;+m? zNMEulrgq(DW^k5vuKj}&+srz!sSr@+%4WiOy)-L9oxOimOy;A$CiV)JmDa{Rh;3pK zWfaq}hHc~hUlCWfe{_Od6mi<784s#4H2X>8G(?`QJv?&?>7|p!0CD{323qxUvC3`KfJ-IMnKiz;JY3q zV3P5sc*O)7seYtb=2`PY!lBybSS!&%UWu9uSwqAH)sQnk`a?R_e*Bf`+9T3do1Xnx z=BSy3YQCXWU{$qi)AE2M^wuswcLWlCD2OhsFrRoI+L5gY15+#dLl1g8PXP&X%>CSj z%)>CuI9UNku@*wKHOQ0l??J{YZb^H>Flb-QFG&k4dE1AA6URlnC#)8_p<2y8l{sz} zqmFNM6~#|kh}Hh$+T@tDog8dpu^cR;N~vpeip(pxan{mngNf^%dTq085U_3VM{r>1PTc8g#=-qEwpuuYa?W?FhXjz~I)xeJjJ!At8K(^at(@Yq+=S~fW`k|Sk zeYk1LWdPf;D0*kOAMBFUKgN9)Ylw~svO4Xvz4(-Y%*n_Rd*(Q>2fE|oPSXc%Ib8n;|Zx2en*7u&;iawiTiwz?S2TYj}zyBUsiJ|5HJ zFW&}Lyomb)5|lvsmlkvH6Rh4Rd3&#o2msX#K=EP*z|Q~_5dhk|H0}|*5_c3hWV0`E zhd9M(e~@W7%UB6opZ_g#La@yaoB>|{FY*RX*M#y{M5a8bJ&B9ZlP%H{g@rrQut-P5 za*az};Rp|$(3LD&ZKQU|3}vtOW*g5?xP9);UiQj%EJkHEWL~+*#(Q!O@UgC(jc4yS zcm{{`V(1bE;f;eE;@V!LouNr9M*^nT^pJ>kV@xw;Th16yI5jgq#hLLH$&7oE5;2XX zISNwZ2IoYi*7nSOI#)ptn5&rA5a&WfrViONGWQc6;dHSx#FgO)PhTWjM-CFWhIYs*_HJ%qb_Q)I5TQhjZNR9`J|&d+(iW`QHmpRn^h zn<19Ny|%oQH8t}VgfVnsn;zCEnte|fa;o>+sh+d|zK<2M($!W}TN9oOvf06{ny<_p z)pTq#+FxRnaO<`T^8e8}iB>0^25iQYCF_+UGpavmuRY=F&oECmQXkOtv{! zlpMBF{RwZX2XT|)$0&2Q=UJU3KWZ4+UbiiGvStx-egi+4;fiK&frYi(%3BMZ)^A`Z z&Qg>&6tJE-3MSTlPB7t@3a9pu`&LbLmXOCA94r`7_>SZ|wnuC`$4g0hUG_sK?kYM! zy$g4OgNHu-GhewbJQ!V_coyZ-xo8g42M+C~5_~*d;WBrDWJi-mi_a58H=Z0C0NT4aj?d)~8>yBBA7Tf3*x zl$TG>z1P;?Yr%t{8Aw^$0pRZGfC`a5MEXdFcTqcy1Pl*A(a>iP?rFe|(nQey9duxp6cjrKqbN+s0Y8gYAr zqoc+~p0qM=Tx>+%f$+A8=4;dl;0F4J^L-}Dq3t|4(Hf|_f+ku{N5PNalCvPLL*NE( zl?598DtY#Uu#P|T0EEnifcdmO2(M2%k>e>?J)`lei7M>D3j*btPtpdTLBV-BZ_wq4 zarp`S8A27Wj!ME0Qo{M{{P21T7F)wzI*0IunZxV@SM)9+M$d-e3YSyCN|pdseYcNA|lf~yGG;LyaNv(U67=yDxk zGez(g*F3wCv6a}_B&`*3FX3O*$IN3seRQs?{5C67?hi_dANt#s7lGDH|HQk(v#m0H*2(jv0hH@59)Oh>i7~g)u!iiom=GR;PFZ5o3j*nO30!-FT5=E?<+ID%Kn_|%7SAEm`atXy z48duL=NUsm&oo_#;^M0Mr&+bPHJQsW%EtLBXWBk<`dxE%5dk`ggLENK3axrZ( zAWhEWCYMVqxHVLngVYA=fCsMBCL}aSo3zrxf(dzcI6k|4@p9zcCwb0&JiBk>SwZLylk;byXfxT0o)xK;>n^wSy)^)~SO ze;(UpjTmAzL-rtN{60h8j)9^2gK}x;TQTQW!E3Ap+{6y32@Q^buAHS1V!nHxW10%@ zXVGvg7S8?)(FY9K{HH^@X7 z$Z2(U9IaWnf;QW3H_P$n>(cC?^teqLEeelDyU`(TR8t>q`C zNg%*_QTxAz`_E0`nqhC}esGH%KvpJq%9IWQdGJqG0D;+j4}@@Z#^?nmnQfd@eFwOC zv?+TKl~rkvo0q*qP5~HQJnr={fN?}$W-|0?TIYdDYhK9Z+y}Lmr;P{kKZ{>hY3_bI z^?~IXn0#nBzz^>~8f29ql^vG$FQQ3?)M}RJJGZPdh@PhnnI9v$7=p%Gqexz_HI6{k zhJUPJK19tE)zZdERFU}_7R1Z@JcDAYY6pF2yB~U$MAr*ZaLM5`LmoZQZ~ac0(J%C=hGc4$G!1Gn)1^e#3W1Vo zlu%WLcuR$NkbA9)u_7*kRoEgbOqa6h;gZ9tlv}C&IIH~`+np^@AD=aYLMZ~4d$E_w){-jo?S*<3cRk$qkPm!V&ZZe;m z%)g8(fHXr$skApnUH4fH5<@N5o+>P9Y+Sf;^0vWC40v6jFdesffx?+&T-%th0%IO@ zN&(Y6(rK!t)2pG=0o#}ve5-a$-gZ6>PKe^mDVy<6QA3ygWU)Zi6_AzHvL~=KlZe<> zyOgYid>dGrWgH~q1eU&rFQzANdptF;^tFMiS+3u|u@4`YZuqy(9*5|65v`-g&2$qC z4d8$0!Q#)BgP#k!h(XKE?ob|2aNeERC>O+rt#l9UfeOl z#^}ZW|C7VT{N*b-Tih`hxcwVPi$jB`DkqCkc?>uI;=$t31@P**;*Kmd`d=O^4rN1z zo+|Dr$MwH?s5q1$^=F|Qak%`?j}-Gquj~`W{A-K<+JWMZ`Cz3Z#ofaIC)%On;$AsZ zT-=L;!?$`yG$cye(4@1GdPut`EiJt7=R;UTn{>P~c1*5Dx| z=Y+L%$W=-MY0iXqD8=x1Q<8!mMKm(L1jrA7z9*$`IE8;~3Ke2E8yo2=aWHvDVeHqQ zA*_O2LYxVS=K zoW$@uS4^H}gy@R1Sr3Lt4-K52@WAP5**noq83#yBbo&)fX47VaT;KfL8}SBJ{n6Os z9{L4JmTs);P2->YWrpKm5ct3&h^1~M%0%}{`oDhMycaAWlJ-jJmp&j}Ne50)2To82 zCh8mUGg+V|vFazF(+Q)vGcio>CTN5uQ8bOn7$+=9Ye@HTpravTnO@OpzL8b#VwF!! zbe|xVD>^Hy%oGr~$dn==TN&g`z>xnR`1Q>`3HY~@O z-fPiEq@oSW4yN}DoiQD7VRAduyR7;rq`r;J7np8ZbicIkLZag|gW1T<$*~~!jSJ$~ z-CDQJSl1M+-)b;`kb#g4e7C^_-11g2feXJEuC@mW7{`Rs#_u50N0qK7*y@7tZf5DV zSVlyILfFE@ejzgcTV43AVtSX-75}X+6c;m#X|ec41s94rSF;tki3?1OVIu#UeEih{ zvDQzQ`he%JS9u`zg7eT-kx<@btZNO{w;7BP#N2%qp}fgLxlK@ZLDU2mL75rHgi#^- zI1@(zX+W00m8cN6xlk%%mR^fxMC!Xxx{_J?g@u7`b3qi#^e&|<&}}ZDp1e|kQkHa4 z1U>xyl^&qH{p-9k0#LhF^ZcSK*u91>>f0gdD`3=!&`e|v3LA;T)#GK%I2dMR(3H{D z?>BhX5fy4!KLC{QBj*nSG-HY*aW-l?B?RV3VV@xZk9)3Z*#w&6{)!;Vc>%G z+m-VN;0*FtlMR^y^KY5+<5Q!XXTzmQdL|j;HQ2ljMUBt;Flu>^=zQ;sQ?Z?@S&27c zY9)bT{mGY!=MDZVsfu`Uw%N((GeUH=Ik7+3-F}fOU=E+$dB}%NCtu=u6f@mC^;+!b zchIFoXy1?o=(O{}UHeGUbz7U+%xzz3!A46T`pagLyaln!!LqhmRNvEQig2{KvU z2&1_wo)+gMOU~`5oZC;?mJVkGivyrf=PcX5x$or6>0l@h1iQDe*iHCf#%UteqLJ## z)Lc73y00=sK%zDh3l`raV4~$P$k2f}rdI^azrDter2SST4RAM~0f{4MKS$7joof2I z(tuWCj6k=O^j6S~(taQ5z~|iRPo&{@tNQ_(pkdT>LM1)*3%#&>My~~$eFV)uUhH)9 z@39td0mr4>v3*c`pHaLe*wLnF?33{e_IMt>%6^GJGiX|<#G|rwd*AemE#|b>*r9PB zhek2&U$g9xxKDrv$?o~XOgELTaBZ=B{>v=JjD=nR#g#k0&6NkN%0nXDPOP8JBG~p3 zY+D4jF@kNM1GYhQ&xS1>a2+SOjuTw;D=RXnxE+@u zf_hU0Dye#z;MHqlpL8l@2xP~nSL`&8WZF6DxRsN3GHN|c>QxfVz$6>BO-%0>I-|YQ zhU_a$>{6mazS9L};Rq(LMprG|IA`qEPiR&yU^YY4x@D3LR+CePf%|X zC~)+%blj+E6Tk%+f_z<*1v$4Y57Er)XWEcoupqY)yN1XL`2~jDi&(-;fm}JVoQRF2 z3*Jf_n~c~&<``8D#@hqhR_5rnI7TLec3ZlQ`URlwLG0t{gxCdNKcm#WdO{$&V05g( zrDmpeje@8hyMUGS6NpJygJ_&^qn6CnbQ`y$7H-<@m(py|jxuQ8ZXZb#(3B%@brCZiA`HIC+qoXd21*^y&vx~gIa+(g(#k?ZT z?sl)$ZI|NXm)V`~<<5H*KL!q_UC>Ttd6$S?myzPVlNE;?Rk_!w*)H;e>sk$7EKNGm z{He=qWxGVxU`4yDrT1}5T@<$3`3!Sum%%^agRoWHuJ7SC(<009rff3>Bw4S>Lo`_v zF}L&3a)^M$+&$Qw8zy5G?~oLl%N+ZH&G``nvo$&)%HX1- zQ<))@MR)vw&T}f69~)bTlADjxO*0qO_u{NmsD$cOw5B%O?iuAg@-n>66Cy9DOfBAS zem;d=47($#6|LeIMoqhM#^7Hupwq`2*RpS)g`hoh@>pIk+K*=00ai_a9!(gEj3?%lu0+-X}YNm%NYpnh61UM}4Ec^-+dsAsZiN zU$XrQJxk-a@K~DplVtk^^={J1z$A=x)R*X+K{rAa)M*(_VSVyZA_Q|BBjShGnERyh zIEt;=lv>|rE=sl!CwQB_1~h$z5W&qDg2LKp3UzKM^R%TH?NJc^=GjY0n_<<4^1Azl ze(nJjlP>TZ{rfHrpCjg{j&h8cMlQgpV@|GIK2CJ$rQzd598Bai z5kHQMtsgF<7S|1!<|Q_|KoBibig@G_OOMDV{SD~GE^5<0LBvf1Omia<@hcXBaHkhx zbc_{UV!``S@Po5>Oc16xK>7gT7{)dMYvI&-lgFyI;y5+bOkrK-)MlowHXKSigQXPf z0|*#9>c9K2Q0Xv1qZs0-5GM+wcmOAa>W`D78X6sLv2BAm-8pLdhhINCBWFD}tI)ISN!i#F}bHpsy(B3d9nH z&C`jtTHY~r3^W5)B|RCK%(KS2?N!>Lo>0DwGcr$`?M&10*6JIA_Hc*WNM0yO zJDM=LqwU<$F7D_}#9X?SI=YQITBIGF&mB$Dj*hS|s7j6_KpcmI9G1=GL`TG`)-H;w z=9w9mqF$>!HiMK+S7lQ?$|_jUSFmE0@0ua*+a~T?7mlPrpOhXqD2_GhVIQc%wh>LN zqdpz7V%%=tMD34?ZrWPdFz*2k=MX}iyLeWDH=cQ$-9GJ8KfC?VQ?KynWJ3vYEx(V@o%s0{IE+CFRSfQyLsMXsOsFwT+6#e|kPQ zL?|vxZRSmW^JoHX4mZfEVpR;V)1$fdN6jA4v^i`Ss9Wi5tvw<9<&NTZ@qvmi%=p8P z2hA@hgq@P4QC;(636Au+Mq}-2JJv2DZ9>`Nk_bAU^hs%R2^GS#$lZoh>jyNYHqqWs zyxk;Jp%$Twc`Dv9j2pO7=%Xzjjdu)>HX6s9FphV}lO8!y!#e8@l}LFV8U_pU4Qc$_ ziUYVcNOjv%>j%xxusGVIH+W0kc>t-VNz)|1D??C?%gZw6wJcHPwMlO_nOC!{Et(xS zUGzkF)(_2Rj-ze!R|bk6Gan4G|mv^6LaYa3cQ^hb_J^X*4UbU z%@ToV3Q{zcRg(F9oIN^h9goDhKK+0msIA4)=5OQdKJe)A(ddDdzaQrqIZaeLj?$($ z>e!gtesr?!8@Xc_xMNksTsp`TBI?*m&46p!?EAEDTiEJQ8QBjShZ7(_oGRUJrrP}y z&8cgu{YySeNv{Q-@R6cR)B@EW3us?i*Q2cK&wb>lq$RbRR=+*A=D0x-Xs2X5OrloN z#EF%L9-8q)4_=3jlZURf6+#oLECt&ed=yZz0LJ5E%5~s&<~makwid&Kx5~D#QIX&{ z)XI+{`B5TV5$onhA2O!HU?*i2J-8 zocstJPGCWfce0Wz?&9<{mRdY$;NeZ_-`TtR@FuS+o-}D2Xi8FApo}^?C=Ld?LO|&X zTelHfH(+6TL+93);0dlxi?K(ieHa^_=kO-zIpFG=bn4+x#ymH?&rIYYqWHLgQ~K3)QO7L zBB|k&YEc``napixB}{T2)|{Q!Ii|{{8mCmZl88pVfzAkCLQ;{?imU^iQQf*wuIP%R zM$(0ilqoMQN1ac_4hYtVuzi-@yR^`B9L9|j=1XTxRD;Y!e${x1GhB`67MjB&Gn`#= z*5=C%g`$x2Wyc4)FZ%`V6=={jhof2OI^~vpoVMYC3Era@@xV!fY9x0>Swpxa;v)mm zMlJJTSe1q>8jpeVn8_0MoVJ)ciLrxz4r|PsMhm@?s-KBOj-s-hl8;G!#>ql&El#6y zB83Bc=$Bt!e#8(tY$_dC_5zk78XCsedN?;EZz5c^s7kA;1!u8{s&on`NOcy$-0jIN ztfVO1cCCT3@&l2jggmt(Ob2Y?3M8J@WB^GAXG#m@hGaTK`nQmQTiMg2jw=Zl?N8oB zP(C_}z(H(5^v``da$>ZK$vRtclv0<&LqF7*6;++wEV!g?l6v1jS_qBs>(%V-`M0ho zJ$M}plcru7vpb1s>O=u@bYnp037I}~AyR>!&(;$jw(~#4UIeXH>$~SDUnnG6%)T5F56MNXo`S6QRqHpx38{ zI;+l#bX?>CCW}lKzZ$KhUMp`YMawsJ^&adjZ<+7+R*N*s*a_D~ni6SVRF*-?l4Ka{ zHmE+1T>R_EuxL9K>MR$kXuD|aCc-V)_yEyuW!*2w&SbWg;WL~4GlJZNhIHi4K1~u^ z*jHlv`Jm=kfI%kAyC3#TJ1(bov=^v_T<@$R`V6hSHFET^9Q%Kn%6@DjkZq8UJr+H! zy|97nci;6$Y2~LQr!mV<p#)(&=@mDtbDI6Uh7h;X~TmRqca99mhn)>>ByaW;$lvs>@5aTq0A&;_d`sSqsJJUNozUTn zdm~p;BvS9>)EE3RzLLWVw4OmHdqL|Xpu-H>7Y1=y-^i>Wqd6||j06FFj&`I_d`|}d z^cWD_+6nE5sE{$f_l@57h#l>O3$djN&kVd38ziQ?FQ!#u<|xeAUW%XYi#JE&rCx&< zHy~bTbtGqr_eOODPnBMxzNAoNdQqRP9*D)Q)sd{}`@{z35e&NXjo#g&(h7n|zNirb4 z5^#iYJP#>3qg9lJ>Lm=qV!O!^cly#Q~VX zpRS$3NxL*Uubz!bahy1Qz5Z=WLKnif;SjL~sUvzYR>5QH-yU3(msQshSAUL=7$fge*#^9y^ zgm2+{0vwn5rT}6`UFoLo3)qu0kxzUT(h1cI2`%~R)*^Ak2L{6gd8G@b8g;=hFIOw2 zG&jrhc_`mO0PUDavM|y5a~429iK3|w8v`KY#zn`)umo~4fO@6+nwy(0Y=V?m zi|==W2VAFCY8Z*{0P(n|Fke*kiRGb*x_xqiSO%C8Fk(3g*FhkcF&W0lvFTES`~q_t zvE6%hB(QFxuP$dWhZ%%O)FkS74d}o~CyeooF&-G^`gU^^bhJF;tZ*R24gCF&_nDnk zz7z-L>%C3Sga0zI2jB?|9x1_GL@vMhQGXbZaZ&tril)42J^E_kk_BmV;)u$ zQFUdG8VZBJ2xum20yL9TA#T_Y!wQ%z!Mle5@1!yN&$YTl4`PLMBTHRe1Ua+wL(xDz>>ri z`4__J$lz~L7hgu2*J|*aBA4@ih#5{UH}A!jWzV5xI8}fI`{Y&OwNiVMe@N12VdNl5 zY<+ud7@c%W9*tKxk=s3|Dsw`-iRSanSq=$Go=*9vKY64K}lTm457A>}9`efEro^R0@<1P$Dz;LiI{?!_oQpl4i+xD-Cdp06bp{k_r7SY*yDGNId!Z`&1QZ!% z@7q}}PgkaWU1O zGa+u0Z2A%+@1ipW>85o|yhm&vSj|(*VNmYKZc%`1B{&03ba(V8aW?e-e9kV3m?klR z4x>znJFatMdkf+x^4(Q1;5)lrk2!uPd9;eQIanlnUrvAUo)N7Nv` z_ggMIBj0jii2!33*-iYq!ryXPgam5cmMIe@F$ACpk>l^xd|w}ABo85 zyT1}GU*6GPODU3f<5ynLt`aAaRcZg5yjd}FcXB52Ct47%X74FHv6HwRbye)*cy(hX zYYu~^1GGtkRO>A>b%rmDy(+#55JqwPuKSS=xw_J2lov@S$*cApmvLiRO3hljkA=qv z@zK|aRUI0F)(}oR}iyxBGAV=)ZeO$rG zfJS_xvg8IO8oFOq6e%R-=jBCw&&0@Rpuba)swe=E1H9jL;ay7G z;Ou!MH1b6aKuMecEqaRrevk(FGOi|=3WIai-kDDwLC}FaBov3 zIf+96PLM!V!DXX*zmM{pa7tja2vBPt)Y_~r(C> zV5-Mc>aNOzW5N+n4`0RZ>!V~U3Aj+Qv$AAEsMe-(txb*iC{vYwC$f*CPA33&530{;a{Ua4OABW&70RH zNNK`Gw(6=pFzovPm3;Q?3$`O(qi$bW^_~5#y39)nsLOOwL+6vc245V*<+h|9Nm44Z z04hIKfXLPFVrC?J)#VWDEXgsFgWd9`ZuY#;=l1=w%|7mS!k+R;>Uq_D-D;Ez|G*x# zd8m@JxOVrDj5opq*W?}Xi+jIvqx>bww9F2r+LBza&I*=!_P7dL>^M0L+H<^t4bj#&JW4M#LIKLJWh^Fd>wICq+| z=Un&->;8A)gK%VK0GgyK1KmE~6|XMB&jec)iY>JhM5#b{Zt}6yGF9{y_^SGeBXR)M z{r424K6n`s0&oG{QVxQ=YxS7AIULkkVh4N2>YQ?^Vv3UbQ9R-UMp}JbL0mayh`#E6 zw`xS<%qgj$Xg#PIDK|NFYQo4wS*>I_0TQ<8WY57_I@$2P*W0&B0WF}r?OCvX1R@vP zPwjWHeP%=x*Q<-|=SzM(>Q?(5Ql~PK@dYQ|l!SM_%zicX#F0%yN+weC)wG@;SjqKt zIk438Hr}7aD5^>Eh(xv0@D=k=(0$?i>~l=VRGZ=}?Q?LYJuxk#BAH8C8WfA~wBOB{ z`DODd>2sm|c$p#d)8|h6?cvMj(>Tj&$$px;*52+%RG%z~u&u~5|$OmqKA8(Y2AMZpR@JYx)xp3IhBnL#|`PZneNTuDv3LCwv z302XjD?HAcvP`=|HX8aObJseF?eLbS5=n8tr1_1Egt*Pl;4L{As*77+Q|>(X zCVXx98tVDwC{68Q3bR7F5ff@(&P6mJ{;pFVU!(qXpKH`%&{Zb5|GSMdnM%b#0r14z z0{NXnrEI9Y=>C$sqo6Yff%PZKa=mgHgq z4?E|m4zPc@#Ep`yYAS24BgTbX!tttvONBToy*P-GTrue;BsY+APqKVE>Q?%Gd6LVa z9hkMpE?AYT1(F!Z@g?ak)h4-3 zr}|zaFs9Zt(sz2)9p=lzH<(+i^J26^jA)WUlL{vA0Db52Wa<#HRf_r;d4qWyBQA_( zv^WaThzk3nIEw|?w1ZrRAlb@r7V(OvQ3fq4I7nrY1Y8&Glv0l^q4wimO@i&;mi^h^>{_yrb(5e-BR$_D1*3g2DaV|Vyf@86Bw_9 ztM5%hYz}9z8svx44yhLPm13F6P?brn$|O;PT2wDgK{`N_Y2c3-2dD)^kF@PUh0984s{Z^9pla6+Q8mEj8=`rDbI&O1YIyIIb`WUI zB=_p#wCZ`id#A1@EvcS&W3_v<+B>Dz^XKPJd8Nr2GGaBqx}c{v9o*Gy{_+j6b}Ts` zvh7L9oOsN($C_Dx)iS0aWGU#e?K$o^b`OH-1)-`s@A2u*o?_dkI;JV_r-yx1o3UQP zl@i#9bw#_N%L{VPi;qKYeG|Rwb9aiDKknu|PX#*_{4n5Q@T=lQ3KhJn9TdCitqSoJ zb|K;^nGzw;af`|bA*6c(*e{yF#Ri#r6~eyvjNT7)=S~+zwTS#a2?{8|AS96Zv!n1; zeq*EZs}$o1Kbi3>0URE|f7OL3(7)In#s~cJ+lsv6=N!WQ_-X8p=I13!Fu9kXJyH1K z@^?q`vx)G()XUEk2=?RWOVRwSVDb@u+}HBs=;a6S&k(+e@MZXuVSHI7+EEwcg#k%$ zB>+-6US3ix-m~}HJAyx{ACpW``q4%Dq4WLM;`WhvR^b&oKu=`#z&Hdr>iM>mSi4J~ z+lu|K-JxJnt6tC=EJE=sf<30`4R?_co?5U*RTFrTue)nlkLBDmlk0IEm z7wo{zZ73>^oKS2F4k`uP+;r#e10#6r4oYn+tYeYblAIN8JT|Pbop3%aZj%ToGm5Mo zbcshL$IZ?iMp6*xj%Md!1O8Yd8z2A|67R(SKJlA385KATY$u?|3YQqTXq7ue3rYzT zm%gc;#kY{E&UCd~Vl9-S$RC4!xlW6&zuFxNS#n2fCq?=#sN6bR)d&+Z--LLiJrD7T z+{skO%Rme?5rcRS#sBt-lK+ez5^@UXwgnKE*cb*aV-O?g`x*480&OB1DhKabGAmm+ zf^fw$j@Zu;L_#zUCmxu1IAsdO|M-k5eM+RPH&f!O^AeZHDcrA1TnUm8s(`L=G$Ba= zfi33sFAAhexJ;#JQqih(N+g`($6eQzNk!LnWwN~MTA6&|t$s3bz12@9za2KPOrC7N zRwl`B4J?xf+6R=$+4k$o5V;@(I=*v3$OGyZWG!nZ~vj#2dVGKPyWoLia7%`BlZLg$k{ zg(CFE$I+1$9C?q5AN`n3o<>ibDutUbA8C-d)p`;>ytgwNAlm?H~;52y*x+67m&=W@3C-M(IoCDV$cWSdoYfZF@GgGSv5`@qWa81+@h20b0UGj+eD&Y=sw(!?}p~ zU*?!-|0~~3s-mw1jTZqh)D(`^bJH%rQt{^6iNTt@kM*3ZWAe;n@+@QWV#nmgkI9R> zd~EPB-5OVQz>6#4ZMEll_WzZM_4m{ZOZ_{RKTJUp;yxmqDPXq&B|L6#Gcbi z4;Y@ z1q{5@>IJ)lMf=#L0I^`v{$No{u;_5Gi2MyW8!j6Nf4k3unC6{^@p zC7Qi}#hf&IAq>yF)rEK~5wR*?_i9}?Q0**W!p|AF-JaG?j=d=Eyn!0e!{Nq*aVse! zBDnpWzO$NNRr}%hiCd}odC;r+E{o%3@R!h-(6ppD*!F0 z$;guGr(*44x@!Oz)-W4qRZnz@JJ1i`SGgfb4mP3QnF@?}eG}1zLyTdYmTM-DIM+h{ zaITfS;aofU!nrBr3FoHL^~JeqaUv0 zFLoSm<(Cv($HOnFxHX$!(x8{bkiTjcp5&t6osRR%49mdDUcA6*_d6@$vg1TB9Ckk% zptBw4i{Y&Mog3k*`<1h-SXqppb_+5%~2QJSJbajeLT*#)UODHU0b zm@BC>{X&>7#VNYK9v-2~@rrIN=xVx4MROiv9dOYUaW3HH2Sk!dHa~7}Q~S0zR&uI% zBOf?;t+^_-M{0Z_3a(v+c6R}a9}6{{*V<@=R{1^!lq*Ird>(IrNT5RWlF5ilP@n1Ue!~69ZqQyLRjwEb4NLiGxC_ zC_GP+hG1XePGznZs1l=H!XC*&WGaSKM2Sd+5Jp9pEP|WD>6N9@TEkYS2+T)eBa*RC z1fnQQ%U80CM%*t*fE0=}L1OO-GOYCKVtb-Ypm;{omY^_XBWHW=xB^j7WqZgamMH2~ zY%T8{4@<`Ax#9SY9FJ^Pa{R5~_*opk8k9JGL?C*i;{jnd$i|SJNR8lvH|9d)g^uxv zMC&LugoaJ8GuuO6OK8|syp#+w8|p&CX5iHo8kU0})rvCEq)JDKW0by z!nW$PIJ-ZwlAgmV==q5?^qjVuo-;jou2?_pY5qyv$UmPbvDJ7I-_5b>35udM z$8J_{rRIeX))|^BwjdnS8`fAB{yDK-2-mkGY*68nih8qMoPi_{P{B2))h7%dhff$i z>GVjVN35eRCy*)Lg=hn@q8UHfTM`%@@{%A$DzaG=u=~pG2FyGH;u2OPqKX=W-+IdusF|TeP|9S=DP-8} z?C#-9#tgte<-J>sBp;^Jce}we+ASQCQBO+9Yb}jIDYegNN1!_(7djD&-40456I)Hu z+ad2;Vl$yPI_hvm*fM{jfdm3oJkVGgFIoUP3^BM!4B7Fp&6K#RZmro-7x+rvHYOFy z^_QO|5r_~NtVZ`%-YumO<9$%BQsQ<-0D$!g+PBbk(2t3qB|)=c7bZM>td z<8@Hs`U)96gMFbGPpnpC4@|}*zmRx2$m@S#q3W`&aytStdMj)~Z?xVU{kTzKgPeDK z)n%_Y--Yj}7K*O`P<1M-QhQODMerWQN~8?TuL^l$eIb)KPZGH^LfbP~aXZPb~_?n61iEs3;#6lT+Sa~M2?~CqaJhB5$`9(M)rBLk9yjE=~?61*zSI_r}^< zdW!dnbe`E~$?)fy#oOUf3_{X`Sln9P3{#8k4|k^M^HWW&c!_(kbG+$7_6ZNpom;c- zu|70dyUSv_%bMNtkk!{PKKq3C9YFUGNj1-1#=vO!`WgnU>!yQjoo!>iR!@ysAx!CS zgSp-=m{{tRb~A1vz7ew>k|BI`3_G5YfcQgHsVF6m#6X4%=wbLpyhOz zy8Kle7`lTv*?_Vj1(?Cw!!Uy(r`fradRMxNd)Q($_)-IAOoOL@j%iISwr`HL|B)Wq7aty3sND`rJy<)cTF6OX zlR5k1Lmj9Y!WD!o{sr8_{8zHH$7Ej?nr2W3ru-{2>^lA@wxeUSZ->w;hNEMJL{>9ntWZTaVrI|i)N za+iP23vt5G%A|VHX}<|P`X4qYG$%N_{P$Y?`Bv}UpfaxWj*x9;9quvojGehOF2>+V zn^{Ib!)ChTOa{*oMB*nNktTyTNt<~djQg_S~v{gPuUO7Hy~OS+7X4M)Rj zm|DlSWw&{61fA!}+JM;DhU^A!qO7hQ|1?U08gWvWrfXi4F88# z*aG-Hd2not*8(J8gFSHCwy)mQfT8T`jsv&ZZO(dRTm$;~S{pI|NlUN+#Y64Y4E8k` zZ#(2!RC&NNUq*TZ32lX1BfduLPH58x|0&ed^O#nz1s#V>xE{#&LCDt`avXIu`5MgY z&KQiwb>5rC(U0di{TRKLb>~2(!n?nC3Ci85-xYeGQM;@Awnooq;J&_d+gqNSE6;k~ ztQU4f4MWsPM8zTMXyCiWO9&lldXN}DAIqO^`U%h96)Kt89{(8mz%P5`5!;>ud_t!F z&3>|Dxs5#vp+Ig|9IrrfwrI&Isiorgz}Obs3-zYvsslD>D@n209%#)6;I*-B$IdwF zCf1K_`P|q;4}_6sH7q&MNZD4s;>mK<1)FUwPE3bqAGFN^h9^B2kt|NI)Bt)bY`1+W zw=+kdlhtXvtKR!A2-J4M6pU>KPj%qOp!j`0guml&BJ-}XSG_3;nq&9X*(nYd>AY>< zNmE1M1r**`_rlSt)bW!{P4ESt|HqXl8CB;P@_af?WpFegM)AF?5?ZwX}7*c^$ktG*}2V1#{ASVc~ygte%Ut;?*f@^8%)txgqT% z-$y;(15n~m2hzb2nbN=rB6VX4^YMI-T;)29#BNw(agiNh3ufljRYBlt-SjU#{MB~v zbl=SN^=9?2;Ma&3 zVSSabKgclynr?&loJ015x||4{{+yAzlE6k5o%O(yf?I zMlq1{V@edOe5>syZ`r!lDe19Kjr0t~%T4q$2rpys;w{kf(oiq+wE1SVgbCzf-5)AT z75AV5R96?6%wvx8;%)=^F60>n&R#a!;dtkyY8IrnV>G0dSt7&P0URdyG@$~FS1ja_ zl3(PR;x2^#YoA?rJF|L|?=i4CYTaX!)l|GNt2Vrhp_e$!Op?3$9Z1?=X4f7ui%Nb? z5ifl*ysE0PQ?ZNiMU+I*@6}}qbagCnOk2_E1=;1*Z ze+3V~tX*wH6!+FP-|vBd=8yJUR%b9BwI#*F5cuBioOo1{ST#rAoPwB{%OJ?$13(Cc&gq{cg@@Qm4fmIHKv45T!&bsP zfcYZIS6i83xqm)#PZ3YENej1;XQ(O7bj8HjJ)@Uti8O2_6IHPvFWGlm9*WJr)4VFS zG!e6iMU8#&)1vTm>;oaQm4MTiIXceniN_wGB%WO}bH?f9Md38z&2q@+9paMf&z%fe zM6Um@2azdoi{C*qWYiF3r}n!;Ax+;*!V7s#@E$O6GOUcIN2gJo)+MGBrM5-Bk3yai zRj0g*N<$JPK0ioJxS1WN0(ZGf$3vJccFGp9mpwz>3U5jnZ>Zx`zKXk%;{s;w4aa4- zSZPP77#Vv=&RXLGjU~&>=m&Bw@cg(4C>NVe-3b8 zA{UCRF=j^=BAw$hHpoAXF27Km1_EjhA{`crEd$Kgls??8O+y@(x>Ha}r?w`<@iep4pCZ}qUE2Vr zaNEr5Mgy4B!3_X29pmrUTp9O^6xMIcHTsV%Xz)|uD(xwm9M``wyL4CpIn)8xcr<2i z#v#vbK5V8AdE&Bh*T$+(p&4t|XZkN?^?L1 zXwd^u*heQ&zn|g5#HXn`eg3XA+?DJN7Z<6mjnc~|q4<~AI zu)_K(vp-&6Yetmm;iQYU$A-Z4>Z>f+>}S*0T7pgSRH@5t&*K6D-)`=XzCQ1gzUq<| z!dtQ3*O7_e+39$EEmL2W>AOPV<8W4OuUXO8j7F%PLJd~#mk@lJg6Apt^>lr0=EHx` zS6MrLt4Me0tGXcDe@ffZhqk3JZA&z5OTbNpyY*Gw{{qkEK6K4}>6)YIntfO74<%zv z0EyZ4Rn+4`V)lTrJ%6UZbP+X>bTzZSdk`8`yR0Zra!p)y{O5d4MmXRy3fUS30tRh(*8G%r;i%8dVHr9Eq!$9aEhf z6UNo24$)`WIM?}7{gi^yQ3J(kigpr=OgvaKJ5-$;ns=Y?9i#UmC%KVY+%d2UxbHpO z0cZaB;?KIl^3uWJwG5Bd_^-zQmcdcH&Nfx&nj*Z(a9_TnJ8Q!@3?>*w0RWqzRVf1|@-Lfw?Kaxv`W7;VYMfbH|4zJTh4P_TzvD>T zNoUQ3MwDzH{wvf6;wWb50y_ki}!f9fwv{7 z+IM2%s^292wQCBBmVgG5evkKWzB8jenOZ$G!DG{g`$v%1*JPF@YVn;hNo}8<`#En= zv5$IJW$i7`^LARsZk>2=zSba94XPPlJ%Ur!ix><)K^d(KZ7k1waZyJHd>B4+z|MW( z>(~&IR^>srra92(#iQ5ot_rv{b5-Uctfd)v4bR1E6q{)^q7&{$E_)2vajy2Yf?;Z8P*xNBb; zh^Khpkx+J%XCf{0g}f;=z`Y}+W{DB9Vs>()9LmLMEl=74<|jW(#My;%m$Xw6+VJ2v z4A-_It%k8Ab?@k@qXtAsQd|@oR{>(2^b(~yj|acO)A=I1m?#aBA+8|GTi_w**U4w$++D)l5vn1Khsm72wGdLqRg zHoyW_z#0y(kz~U259a*&v?^R@Ma82&3V7ASu6?yzd;&ubcVVb?NwM~qBE%JFfpu35 zMp%>By)+>>Uwjk{h0wnrXs}|$_y7L=|NZ+v>EAad{YU*fC(F>c<7WdscH+Ml|A&+Q zXZ!b@q2Sep$3py<;D61~|M&0z@8AFX{rlmlzkD|hzi2E;_f-TNLnL|E#Di*mVuWpv zIq9|-ZyvhP+wSrOjH{+zZZLT}baT?U5VUA!Hy)3?u9=gvW4yU=Fm1hkNxQ*_j2TVKjUf8@D2$Jh0#hd$8neAm~N^a$oU z78W(?>-gh`Ll$MXjH(-3@2j(5z-)eL4)BX42{-RG0-^bSi}(fg{aPnS`7>!=W7{Wq zbv~|k7FuYduP&ugYyd|_}~?uhbY=I^&0nf>&1fXAjn^ND3}7b_`(rA)1a#fD&6#V{s2;T=Xp@dFR9FQfiK4!0Nz2IVZE zD5YJE2Gq7eypKu?w1KB72avtrdD^$U)qq8%1XSaQPeR5ubFnS(RYQ~WoPn#&c^c3Z zZ5Y?yL8?9b@q<9Zx|KS>+a zvFP|EGvd9s3*L=tptGE>_Yh}%`oEwZurUwD&Z4R@nI25c#4`m9KVF7S%dw7db`=Y?7AZJKhD{9jUUIpV79f z)L)@(L&zNyj|U_8efS@S6Rns$1N8*47}T}7hy8h$Yj++(QWlaUQN(YB8O=hPKByWW zTASG9t1}fkLg+ZMyw*{tg2%_UdD65vSU0q=1g#~^K{q<8-0Y9MXPGdFs8!9t2;Q(U zB(h-xH9VL$ZFsHTvpn>Y*tN7|l;yN|%%sjVQj_~e77<*HKgBsJOebv(%p$8e+;K`f zs6W1e>aP`flv}d0&?@S&W6b-Zc8HdWk_hinOI65L8HZP2DAt<*!?MVd)6r$1uu*DZ zfU0!1nTIb{|7^4GQM1KX^#|%=@5<0!D+6)$jKrb~ zTZD3T*r0)GIE_Wd>08js51xj4v-NvvOxXI(wTfFJ3x;AS-UqODPCF8{Q6eIiO2o>E z*asCeYe(}g-R}b(J;&Z%2tH{fThgt?Y1G|L(q?kYIEps<%x-|Qn>|U6uH#2x>LYBI zw56ky8tm&bdJ{^{;$6H-Q~Qc9EiNn7n^fWfYRNJ@#O=HztYi&Etfq)haRh1>h>1P-e?|Hi;O#!wuJf~lfKQE|uMaEox%tt+>XirO|ttZgc7XNJ8(ozZsUL2_R! z26UXgQC-k(?sH0wH1#8XC0EKM6frSWo=q~csPP$6pABKL+i9}{x)0iB zoCf~gzK>!&qkJD3J;QMTHtcFWH-x(Aj;nNtMSLBb^-9dZeX)+#c|x!yTPMI*OU;P0 zBM1L93tmt=*K19yeCI0DwDO9N>FSI$`{Dcb|3_8UsR;v_n=^c*vylqzG2p1x_%}y_W4cwzc zG0MAKZgKf$>LSq>p2EgKXIJ2pT0xg~RBOn(&12DX%y(u@$G){@eudDG*yKjIzDZHQAGk=75HXpbssmtZvajCkpKAs0 zIDz=eU9@{9H>bu{ab>Y5SaD^HcQRVSjhvImrr&3*$Qt7{YgYmZh;qDAdBC>O89F8c z33%Dk3|ksSV2E@bXn=sd}@S_S1>7jvBnfgoiWp6yh}TxKWeNo-U-L*%EY6yO&`?6;q|P3 zm$B6B5<5Xb>w;Q`JYPez3f!+9(!bG*enh|12xYFgI@9x662xOky$i*Y@%d@!^m}HO z2>8s==nLdZWxK^8JE?KkB2!yUa^)-D9f71mfhI&|WtW{?2uBF7KeNjMph-Y5F8UMC z^xAi|7kac7SE%&_;C!qCI)=zvJPD=~<)`G*TcMfonIw6X>3s{fX2ulMJ3wa zpF`^hyTv&h@|UN!m1@za(jGGhk}%YDhutvCBDhxY`vTw;3#MUPs~NImsa8Glav%Vw zDjL+PKo@!#)bV3s62!N2|p|3w-ZT^3iJ9rAfra3^u&@lqV`CGrmXJV_N{$vctH9@`Pek3Ywylgd<`t zM)$jw>p@m1u%G!T|Lnp22M;v$Y09XBpahv}T11O_&>sO$$uYR%3recPIpF&!A9t7z z9New!4vxWg5Np;j%F!SbSe=rk6r1v2JGeK0*TLP6>PWCUjQbJ&DGujp-xE+iQ)r7< zA0ml*It={)E(Wahf;_?oevv9eXzt7EU^$F-H|fmarq``m~ zkq)r;YvMwzXRPnV#n(h%3C&mlmBR9| zxQ^A}#681fntI|4^iQ}wG(|n%C4t#Rz!HoQ;h80s^^zcLU z(K>rlX!2ljg57-HM=hosp(oY|QifTFOE5@=H>ZgVN-iCd(h5@6AO{8)HtsfmI9z+BN0@C3(TIH#|-{-=!XaS3q|R%1m7B8n@}mN`?HA>S!G3M+MY6% zO?IL$<2;Q%rv(REJoUb8Ji)(gsI$@mx;CAf7awS@yH=gLE67cKT3;* zQ>aFKv}6^7QVKbbx@_Cgzpm!$0r8$bwmBWMZFgqTPIhh@txE>Hswws7^87fTT3aT} zN9tgmRW;&E8sFIct6SQxo?bL;mBscP*pHp+WPE?QXsq`ATXht^OXA;qR3oN5ZTA=m zv%P6GY5~(^VSp`K?HgCL*f$0-Mz5s?geTfU45LFZ%CvK^y(WeQh!H^Q?+Y%%DC3pp zmd^S!jK|(UYXT4XoxnqW0}o8J0Q{I<>)5|?8uWHy58!B9F&yh)`H5PS*Q%!3o@n=4 zjICJCQ08J3I=quA|8tPfAvE@)i1;?G+SQT1Hj5uuo{Ib`qaZ{78_FB?b;or}Y>kt-`?>?0X!M=$ z&A_J|clxrRzNOqkyrKe&&o26V<3nN%#tjY7K%ve*N*qf>d=(Km6UCMVF#6n>G}AFb zm1{$Dv{5`O1 zJGQ3`wx@>WwF0=tpPp(==1;?lEb5V`)-UfvOM6|RrXI~E>27S@%cPmo^z$-kC4!KE z5r%7qZoJ6IAnbtX*+cK4qx8J5o1PmFvH4Obn=kE?=1UR&37z1djl21$=>=)Nv{RZd zJtNJR!ZGtDp_wnS1$+k=shKYYn~rlLYmo6m(;#F(%XR`UF{>pdqS+@g+6fb-QDn7B z?I4@si+j-w%$;8%-fSJhFb(G(_HJTjN5`T45glVF zBU%1Tf(A+g=?`imc1+C|#Yj5%$B5JQQSSD(AuR0_u(aJ?{c~er+UC@&YrY#IZCJ{8b{7|DoqFEqGE05<*JZ>0Jq9}hrvDwc*bgs?BILfon08(m%`zAN9O%cqO4#a?HKs@Q9R z_+0FDs+b#ly;>B+UW>)F*y}toNqgP;CA^3XBW; zC#m!>H^(d`m9n&oNPH_8k0lwyPzL2j`Ty-~x*K}{oC3CA;LyM&qYk!jHI0HoBb zL1dg$eVhQtL~(^QM($lktqN_S9~okYWB(YO47GyvNL49R8j$Kvj}~}B+82*ZBzp}Z z9`)5_R7=>t^Lj0|Ns2^y!!6aO``;KBoqWz`<|A;Mc=|X9Oh(5|2xqy(q7<#7sdR2x zt$rtt?Dyqz_w^XEZ|P$PT7RZX!@-?GZBopr7P+;+5{arUmgrhaq#kBO-Eg4Fh*~A0 z#8Lqb+a@LuX8*ETpD_KqX6-Z$ZPo()#hUeZCTiAubwirePWEIyLd(h(kUQ{n8dW5hUrR!E+-c; znOo(SmE{(neUsF*Wb3#@TMss^pt&ab05sUMYC0VgO4ST;>RM?i?-tjQzznaM?gZ2) z<<4?gO&6znh}5w%$36i~Dv^16@?Toq-{){zSIn?I;kU+s|11vtNcEt0xXrOQ?fVGp-xj{tV~i!bR~2cXKD(JmEv}A zo23HdM1+0mAccA2Vd-vn90Is_eSne%;(|0A_3CK6L7!2dq|b=>QBvd4*0d-grU47E zKekd=dZ2t+HWAnx*GrZHC}HKr{7w)P2VZo&>L&}s3Y=w3aFTGdThoB-XWk4knKTVZ ztx~{HJQhaWJw_BVmMKGT4$js%Ssy%*&+?gj9L%4H4Tohp)X3R*@S8VVd^t%)awL;J z-m~#zZOV=*kY8!MD7P>VQre+PiR@OQMguPf&ub~Ji2A1zv6LJ2=fGjY1@u+CfD7ZK zqmz#?mQc?fs3*$K)oHjtLPO_%JfwQ3Q9PQY?`T8Dp{kPgGP^03{c+?Z7@CTwNi0pu ze#wyRoQ?EDNzYTu{v>h|3{A~5MO^Wpvo|KPKZBeELsRuM3vqskvL>2zsH+hRLugJw z*on*xhTpvD;@9W@BLZJYWEb3Uct~y0OT;(M|99G=pqsQ_zHZ?E(aTmH_wqACds%#V zP6K|)g^i*zk$=N9EL7Y+Pj_M_?V#zD|B_?3#`zkzC-CO6KxaG1X#L>~0y2V0TGQYXo4uTqv6Iw>spUv~7 zhURpFgJUdJKde7{gMR^%YYyW_DwqW#*lWos^Y%;%EW(Ki!jyTF zNNY?W0BrfCh2v-8+h@7GqsX``=%j!a3b1e9fFIg0^E%M5Fb-@}_68xNb%w>hJR_}H6eM~Bu+k7CSO9^H>I~g zb$~LY&~Fws>5>82q^HHr+FMvS2V#vYHPvnoqiHpsi&Z~_=aPN`uV9?e=`xVsgAbx~ z|5}F4G(TFoOo!B9!$c4poJ|el5>u~=^{XZHEM-$m1CdGolIS){B~tsS+lUsoc*M?+ z5q){3jDpKRJaL41=SmHN&*)Z z03f^{<16k+a`#pow^-j}BhJ&Izd#^)KN@d65WEK4QiD!AR>woF;v~umM^h*ucCNO6 z@?719+=@;fsbP`1Y0?mj%v#KJ)F3OG5}q70$7~oR?LW52Bwt74DKi;mYHD*%OI8X& z!6q@C3@oL11KE?THJc|TS!*IH*;?}=aIy%FMpa6c3^#cO8-P`A;d09w8?A_0Uk3y@zyYT`$yG;6F2HQD5?SyivCon_Px?nZ?Ihh#wt0CmcJ3UKAr< zCS5jl2Kd2_`PN#iOF1AmNk}=-Ro3V#OB}|JV=#Qrlm+M8la#e8HPzN^iE$cXd<1Go z!5V9@1_^sN>nLPt;bs0D!nwxkAIUhM+>?y<@8#+8`pQZTaSh6%PeOU?AVIlALNUi`b8D<8K~<2Vq{f;3hP0tc^cqA8 zZa~WrT?bc2r_p5HIfQ(>J zyp>0c7i9z?7IJn&R$L*P0fK2LNFvoyp+(&=zZbdec8-`ktnAj*tmAS(T?DZpnUVid zrLG$~g-R<{YFr1{uXG}R>sbS|_2xiV&#^za==8Y0{#Pc4eVH5cf(-;?ByalKoM@?WH7~g1R;#Vn7k=JT;4xqXzm&X>k z6+lWsW~}K}18_5zhXEG|0<`~eV%1bfu;QMo6tB`AOum#}&D(|IP;XLETy%8Yp8l@M z*g=IaOF0Q~)DuWI7jpb6$1#5xxMM5C`bU|U+)6W3Td+607hA9^KocdX42(B>-it~{ zNq;A{U&roRv)8(K339nZOZ3LWB;9{GObx|q4VOS_L`2ezDX|K<(3W{`giJR^F-%-y zTs-1>r8+~|%kD1nqf(pF>K1x}Ap;ImbD#Lw8>B|HCnTj69a`sSuB z_yswV6PmAw68NZvq@&;w$K`zJeFbB+h12980k|}PGZ)>^(&jg8)#n|61ICiz#$|}b z{U;m0MH|PsoxzRE@iMtJxY5Ugf@T&Atj4o>BYUG>FZVmj=JJT|NNGqY^f-eVx3dy+ z1Xcr01f>$o?+bi#4Ghv@U>jjg_|22}Dc!6MrZgd(ybb1ATF)4Qp++up9Y5Fe^Im># z;OG5}$|m;M%&2hv@Uu?-bkmPWJ;x;wMuZIks4uw2KeDAv4+89}`ZL$~QwkOvd^r-S z=r*b+)Wv>>ADY`u^>{(A-&VjyL1Ahe!4M-qK*xrfsJ1RJ0d}Kyv^tgpgjNkkU$KMI z%iGl&F`!pwEK4ai!T%jpYC@(KmnfRdV@l1|U|*ua-u6B+qF@?2-2lE5!0Vr-M%UF4 z0?WDi->2v{+S_SsfB&&)G)WTyeCe?00<#H|{V%=n?NsQp_^jeOjMDsxIU5hewo)DGTr0?0GG)5wAnE`MfVA&Wh_BG^=6>wG?aR)CC(mY zt)+0SiM=$f2w=ax+-t%q|1@$y+sG`wiWkK!OUfc0;hlEq-l|=BH?~F%4N;On)}~;6 zP-j+xW1W3dB~%W6VbgH)Bc?{R2hAbtj*w|X@N*{QCGtjC8KZW19f>JWqXsLXkn4l{X_Y4NdAO*@~;@AiF8~}WqD)9-yYRS;Kf7&w>%LODK&vm{;&0? zH&7%u8Qc))1XPkc@id=pVm<{N2UP1O_Zl?%~G6ynnd}*RUZS2b)9arCR>x z#W<$m=L_=3C4Uz1Pi)n|nt?(6tJl$7Q*_`0vvaY?p#PGN6#4|(P#`{pu2QcKM9vQl z?xf(%KxDvg$C49|0fv?fR~l`Zl77$FDM@}bv@*-%7JIj$bMFMc!8@?$ znrLgZ66huo!C=8zGMd>fm+{8aOawnqV3oG!#uOR~#g2{@r(2pnK;lpcPYgf`&QT}W zwpZxMV|KcuV`X}~Or2Bg*j4)>7$YruP$REb0z3|FRFEgc`CLSSd+{$D}F@mwbQp!Y{WjdsYrOW4Zxk{VusdY{&rmt0xBjEz`SbNL56aubh_O%*h zP!0tRAjr_Nw|SkJT97LDf_h`D&U-@@4~FLC1R`TsrPVJOG1eX`$$^2;*|DqAL#1Pl zt@W0iP)QH+qj5%1{u0N56?^07%r8BZv>9b+tZcJh3Ne2OWT1e-RPt%%<}!FgBHlMB zGmM5D16dBegA|d#-Y8LK*FbIRX(pp<%T7J2L_nyW4qTxVf6^pbj#K_|;#5bB3#Od% z2>&}oBr5H6FlDc=DdK}sI-0YXFPL9hxA-&h(Xg6Dy3ik3UM5N?Pe&>b*#n3KX;)T; z-@bYpvj+cf`%>1A!I1WEl12e6^$a;Pq`a31T`AN&AqAVi0@;D0F~q(dr6ndq(LGFx zSiLn-R@OeQ(iH zY+)O**qF!}IwP&@(c4el-)`v6LzA2r1#|=sC&vpnOwELs&&E?ajI+Sb=?Iz~CS&J! z8qNux#$7r*pK8OFvQL}9&m&|9&2e}Xy&M~U@Hv_%!L?aSgKM*KK+oS9T1zVmgkLDN zx0Lx|!c`et0(^d6m_nslAaZ8>kt&Asu_;g|3=)+8FZFdFAkPQBiISAO)V3X0cUn|4 z%@o>j~8tpk3hc5rrtbeKT81u+;eSY}-fDVl<}VEKTK= zqgw9CK{Cs{(PQV>wwLG~owfhKvQ!Thsr|TOWj+k_03r}It=LhC8g`Ug^vrmcx8X?q z6cqM3tJfS_e>FfYS*jR93k^$y`q0e=;;??$yN$S2VhUAhXM){S^*}ma0sNr!^HVE0-#!v zeB~(dA$?6EaDEBS2xj<_n#A_z#vmiI_%E-}RUdvUPOL5E8I233kM)nsf2nYh-8X_b zvlvOH<{gnWNJV zvEOg_vwjC7wR_bSzRv~DT;;pD;S6I{&~S#)Dr`8zcwO6Yh7eOPYdFJ5O>8*BSlJuS zFj^x4Gu^QttJflH!&`SnsioVr!z z1K>#l9A?Cowj@<>jr<=as#rUeA4CvF zrC#)d4OGddAmVFy#iU_aSV-?c5(&ybnUn70q!b_uWl}_Q($66&TcluvqXKWlx8e-v zwYy-fk8-i~Rbj#-ZuRF2$NFxG&S(&Q$M~FfnlPFU?NrsG%xf_PO)Vvb*)9H4UQ@+F zQA7=a%wi7`W7bI?_gB9rJrqW zt^(mw>7uRv=%ul76krMKhnvLCFuzH5uE{8#{D4nC#&-1_j1Rj{t|wQ=z6*{EdJqGD|M~Xj8o}=6>iT>t!K=)cNQR%F(Wh;sKGjAPFBmj38v;b zQxQ5}np-&r{lC-f3M<_xC@FKez&L|*2G(YQ$%W@2ZcO;x)Oz&}rK7!cYC}Ni5Nk)&sQIc9Rp)bhPBKN{JmAzX8K+&?3Q_tU$!zCwRr`m4S%SpNm(E zdKm?Dlx7imx|vKgh!3Qgc61cmDQJEmYP2H5RA3&~wv?*mXT5h%0?#6im4Xak@@jz(XmG5Txz z)>W}~0G+p1ydIY=NzEjv{P-#`zAr=7M<{zWeT9P<%wYOk*i;@5-!-uEzdX=B5Lk<| z@F-55?$ssIR|P%*OU;DM?RDJI0j{jJ5o)8n&~Ncw1}4`)QM+i46j!_ z7UlCWUJTXYmZ%rtk|GEf5Q{qbPDEUe*iFVOA?FMD>&AVm?~1d)4gfJi)!%&@T#w^8 zmN(FBew2@rai{f1f|Tn z9)6HSI@BdmT>sfPf#tx+eOZ@G- z3l!6Ryfe(RWYHiWM)wt%2*r+4UTp*I1@jvQo5x@)e_{z11X>W;ouODT8GC6T1C7ow z3xQAms8USkz|I_(6v30bt3j*3JIX^{oIFHaM8>u%!Jnk$nneGCuq-W1(`g}YHhKOS z%UVQs+C@j;6*><7Ode^HcgNE6UIX4pVUiAaukU7hvSGD_4@MK0l>r5LV_06UCa{HI zHn;@?v-e>dojV@G6JS}R%4fE1PsPa=(*NFOom87ah)Xn2<}Rm!=ReKXL039zOlz*l z-wDqrSjvd3A@-bi7)ee>egrI#j>Y)Hk#NQI`n&WxP(ZaNH9wXozmIYO+fp~>TW%4D zq1YocjSv&IMKv-KGTcu{YuX`^2uz{M;l{WH^h0d>*r_z>a4^)Yip zY<;vJ)7Ho52%qOk#~<5D!(ajH{KNEfIGDl@n5gB0W?JFi{4^_^fuKTH>S-6i6yKvy zcvv$13lB?QNf=#Jh<_X)8RP;8jiCfkA&-Edp>WL6?YRj53N0Nf?-5^bN2*1Zz}e`U zQ8=Igsk?@Qy~5lCm+B)f*Ky@FT#atqzSpCe>110}R%g%O(_9_)8k!fKY%c$3u{s>z zi^BOko6AoYd-V{YFAbIh;nNsX6`C>0aWb)=#rCz?s5Ws@3Y;e}Hk>`0tsK^*F}A0i zr(wueUw49sO^-Hgqzt5WU9x>tI9hB~%GQtzgm6@^G?R)z{G&ekV_o9I4Q5c;)S8An zBHidT9QQ{yy+jd)z#XTl#EOB~cdMOra$bpUy`P4}0@`HbCUcS-uiV`%ogjQ`_J%P4 z_I0In4ZdpVxKpLv-6$io=yQ}yZ0JO1ZKoXK$%z1l6!k+>)Fx7_pF}C5wQIze6M=5L zQnqz6o0GB?D|fHQ=d?jQ!0-uh zUi0G61Do)M;ei{(8}5>gG@cJZ8C0AN_6`RCB46w|z{o(o>@GCiXk|X@6Hpo~I*%ig z+A%R8@T@*4Va}07>0&-&aUm1>;CC1XQ#8~2w`s9ywiI0CZmeMX5 zOKBI3r7zMBEeY4G2k1WApGv}2OeSGwI;~Zq)eD-~hzsnS>)GbkBz|>RTXdo`rFqC~ zroD!^G#G{;QZ!Son6}9C#NmIzFQ4|u*s-12*vL~Pn_{L?fa8`4Y{+SDuq1yp5M^n` zhaRzy7Ua9Ex+?!$4N*30dJX(2idVasB!Q3)cxgU!_@MSza)61m=`ZqjDdDa`@1p38 zk5`AK=b-B(t%D**-H{TiiK@oXTD{}k+D@W*QWew3Yr+~^En%H9o-%Hf1kP&v?BnE& zcNlyzy52A)8*o>+J>qvbPP5TYIp>^@5tPh5QKu_itSK}Q*AyCXyiz-+zUbQ7{*lCS z1$!nfhM_ISTzHWxiqV@|Y;0FQCV2>T;J}ZylgDt;_o~)O38iwXD-dND$)D=*F_j!%SLf(&t_%eAJsrG5ijWCs_ zO+BD&*BIxQq0ufY#6j{3ks5~{V(8Shm`U$ScR)QzoZ7A@=Epmzt*Lpe`uDuUN|#58 zknYXM7SpI^>M7q9#JNAI<|zB)L1_q*o(FI}6w3D-+YKPCm-zogS<_K~*VR5xAJr{Z zTTq0kdz?7#z28GOXxPt*y;g_^b`RY~>-uBcXt71RLo24F$LHvX?{d_Y)H}!LMWnyg z7Whokw|pTr+PnaNt|%*a)_~KyPyW*+yxIB-l&H{d8MM>|x6u#@Zj9hbqJ`kII^c%} znu7M4D4yFAr&Q*?kaXSpLrwU=Z5|i{M{rJmwS$#$2_d-FT+w~A?TG`%{lSol>e`zB zQeJz1e`vKn5VhFuIZA_(OL6SC-MtxKp^WQ;_Yt=_bTbXpkAh7WiaojNS_PcL1Op)O z0#=Q+X-d0HfYT@cDqM`Q-*K|GOX-4l!Wnt3${RAx`WCA_v{0{XqmPz3(dK!hF&vsd z8-;6EsD@FswfqVPu-*lQ9?Wt+#1mP@TKLE;14{dpaZ)-@%RhVjXgLov7})EI2!kypZFQX9nDygF$M+21Mw}O}qPCjOY#o*Jx97h6oG;jyD?bw+fTM;?cCr9odQ3SkHWTpbY-}55#VM4jU@n{{*Et>Lef!84 zrb`U}n`Zmq8`fcd{dF`|yM<&$2BjZi*Dl1t?^%!oB!rP90IAFT)lVVeU*kmYhy zOJ|xe+>{8U&$Rj1*M+Ih&g0ryNa+ZDy&IdYJoxMeQ)dXf>XLxKMTIDy$?e%MuoEp! z3{x>wMo09R8&-u#5SJ!M2D8SNkM!s4*=7wctt=H?LsYnaT7`=uJxBXQe(BSx5Z?w zw{)a(EjlbDl|jG_Xf*t%5gCaU6hJ}5StRT+82vZ6Ty76g$rV>nV`^R;ul9&sV!!40 zRbty=sa5FfC*nQ7zm9rdnkuS0(GTZ|-aZtYnwn<7rtLK1rh+GMQM*PMBb?^}_(_d6 zvHK{d@}5TR!fFXu^TcGX?u~#-Wv0xKwPC309nZrIk-eS0p)i@)*Be4Yc?e5Y=zdiH z7?JvLe2rKK-#O2*`!h~``W_mDFBc;`8 z(N%UAY!{a4?ac401QT&=OieUhY>0!yp0j-L!m4X(R$4u#L%-FnoC;QV2CEMRtKlq~ z3@Vzdj|Zy-e7?akC)=h)$nTQtV3gP|oh%Ui%>Ed0JXKsTBLpI>Vl*OPrzPX87~9>^ z%+oAzVoad#bk9z7B{>c94MVJ0O`l1^cwTigMc3wdtGNH7v89IC=v!Lj3`k7?JDke@ zDuGjTwG|rnRaqQhhn;@y6mjR~gs_naQ&I8}57u|wqW&GE!|M^ZCsBx1itW19m$Wqo z4h0Lm#p0Ho(tr=98tj|Fq?}T33Eiz5K{L=-0%eUHC0r@Fyz_fpBKHMU;q#Gba6;&= zg5Z*U2<(`Ti|^CY+UFlitN+H!k>HY7nwPwWiD_}}x=m9DP zt`i}T7~#=)xg7;?2>lTZAt@JY1AFbu7SkDRF)p8NK$GS`7B*4bxd|tLVRRPJWAFIn zF^sj_AY!}XMNNNgkY%00I`S92WUo*Mu~vM&v1CvN67Tw{B#J`6rtF+AkwwE~=@!}g=$2E-q1+Ozf&#lNA&G`e|S=IJ?( zt~IBTNvS(ZhqkD{6YXYf^}rp@52*^>SfG((qOzzP)^z?Sfo;fo<9rRz=G*kwIL@wl z54n*oxN!|%+P^Loq8Dg;SJwyX_L(Z+pc{yEqdV5AH`%u9Y|k|lawWm?PR9Y;j~+u6 z0RfkEpE1EI30XrSJjp5vPh<|(?JKU30QTW;hfAzx){`_{ep=7fE;B}Yf55xylPzD+ zPwU%d@?F+4Pk&AQTj!dcC#b34M=G%75lQk+buNXyEsniQx@_fdFD=Y2tGgOzR%kMZ z^L|@kCg6GvC=QLW_8s2FxV)Pg-F<2nh%rXy%Sn+}BNE0PDIsWJy0C2_0s7npnx|Q~ zx+z@_;1d;QKuV02O%*PrMbhKGdrKAz{lS8?t$_6Pls6*@QBe$dI66ug|~ zpMiTQE<1b~N_>0Q3%ItCuVO zqv%oNL1UL<V9R> zR_cW6w`q=QqeOeHU!b36Dpj{?i-+@(g6iEw)<2_>^<+!pe}w$7MDqXs=%bHf$q?$w zgb;@p@%)|G)wa-lB5M+32c|4enK#*>t{TWJS}SmeH3RFCZ^ngIgRRPpt^Qa@ja|W}h)UCKOYpwac-gYW@#4yr%Ci(0+BSeEzO%sEEK2jIM(0}E z&FQ5uvj{oQIl?QBhngrwu-u*(4lx|4Nx5a9%M%+?(4^ovJ#MgQUoi%yDkzEouh~RDZlmQ*2L>;%Fd}26v`&Ee3D;lBK~L1MN^? zHscv`o<;p$)!Kn8ln2vQGNEfC+yn0nUc92GFQ{l(R`i~WR`heGi&1>z7xRh2G;%H|PyFiTt30jbv zgv!)yMg9>yXL^zG1T|M1)+X)%BUJFW5sLA4y4<*tk|>TP%AyT8zlf4Mdl`c?W>VjXz6#be|+-&fgc?s(b0IinD0*Pw^}109)W5 zYLsKG=gdmGq*#LGJ&I{#f*km!TePv+*8%v5JxLCN5C6|QhwZoA>idfd7I$F_Rl z*xKI-&6cfw^KO`$fQct=Go?oU6?nPdudcbzi zGwhf!3|%Cg8c8pgnj_r%pbSP5igCNdGkp|gSKkKj3fAhNkL2QK$J*$GYh0ux1;eY@ zBPt&LZy~#u_ZW&+cO|}`8o>9T65ns1#rH$X0((}dt{Z@`3V3x}wg7)XfWMHQ6cSZd z#Kxk3SZp`x4*9!LG3*-}I!=M;+rTv?xNmh#O!pQPz@~h;W52~#&r5BP26P>sn2TS zF0T;>pB@J*0QstAnUjr34np z-Kr~9?~jevQNR<`zHkfzqi3H%mLw+^FqctMH3X*cn;CE8$dbiO(04o!fZ>S{ZIQK& z85XijYK9(Q(na}C;skpE4lcRc!6o~X2N&CROus-6#MdG#o=I%{9j);RrU@n?ac$mv zgjIf)>FU|QjP(5;<&k(%!$Zc0tY295adiD1dc1lK(7hl_Rs%S8@JPUR$C`hM3~bIZ z{*N9Fu5=PbdDgV*Qmj@DSTSMtkn;3-{79an5sNI@hiE5!;y(=SyhSso0ca+{o7|-I1WC9zYcb(_AbPWa_YE?d(5D8V4R+j?t^!k{V5y^{Z zQUtAbE#wLrQtU|S)vQG=CO)dzOh1@-0V{7^$1`A9l9PNA^*kPX?X6|K3Js+1!R)OOa zMh{-lJ#?7xrn=crSg17H3;2)lYk?Q@;TQb6j9!08udE>BHMm4Q4eITi@Fm`ToL(QH z*Q5OU7`=8qPRXBS=vY%ZbEoz-m*r0LLU*4)0KvYFqqFt$E0@0(=w(Txxuh@POVly= z#q_#@UvHz=Z}97v==HY83GmcJ+t?viXY=SvOc9!-aAQ9vH0OCTd^HAk<=CFe2MrY} z)dJdclwE-~LteXo7-l9*$`1@-)L;qG`>b%a=}RrHF9PH7boCHku-jio>j8F`l2Cl# zZpUi1gSogj24FJkdz*Q=g?@W&hPX75>_H@hF2SWW)xDL&hO(2*lAWBeb<5CLn3syf z>*4@vV&(MGDnvDIIs#0dN~9=?W3q;1@ePCYUOPtIn@BP?o@BA6lg&(?O$D zQarqBAo3g{(<#!KOG=swz>>9k5TAWMEYG$kY9_}iTVoH#4whcqj{k2- zN|=kcBLNVYLFS<=E{_?8j+cg^qg%$@U|(Umq04qRQD&M^=-asNv3EVbf!Ot&@5)%d z92}fuSx3jR-jm0-48MY8rQ(%l+$C-99dDrctvK4=> zSML@%vT%x}neHJm(NQn-sZ(QE^-x^1?gFf?i;26IPtjzAw-ij5zddx2sHuW zEEMhLGW1mU&Fxz8P_nB&4qHEp28u{wr(LRQ3yGXmBO={mfVA@Yy;6kf9rXGzuc7x_ z7#pB?zrH&zHQMl1I)hvwB)St`Oi(5mSr?NK&0`5s&L>Ha&0oR-pb-TzzCreTNPHk# z1+$Nl;xoY*p#!^|SJiT!R*?z`7=tZWQn9v}w~Rf_RE>k|cWGeqF5JP_LGSyC1965q z5LQWLf9=|-=i?lNA^KF`i6-j?!+p5)7M)G(2(U^?)AWIqnDUl+sp5p@&JH3)h6oXG zN?O?*Umzlz_!Ocp#HQ{+>4n4#j0qr>^4!S?B0KD_ zfB75MzFin}PPm=MY=Y?|39@Y0d2^g4w}VgL*06!$m!KH>xA>9w`djnmz)?TTRW*55dLsree*7J78RD z@ zf9n@i$x1lPCyHm*4k@#Q-IH}1jWFSwfCRP#;a5j1G77KLgw?FZHRB1)Y@>ipIw@}e zGVh74FJSLqxgx0v8fm&aBx$+B+zK{PtY}4VYc;8)h9hkcc0L57Vs=vO^_s(zvzwY| ziCIxpqlv!z)3@lXTKmq72o*lKt?E*+6rZ{-=m002);=`CRIG|H71b^^6*Vr!njy8# zx6YTk{8>#+XoTZ2+}abLmDH52Oo~uBdVw=>Eecx4LYl@@I5c9Z!s=)5$RA7s-pS4%mFBU~*c4gnw9E*}GgDaa#7a%s>@+VUDL{hJ+#ZN zRXN!zVOJtPCm5gJWeOJ#qP_R$iPHpy2f`6A(ZrAd2e?;GrC zp0QC)P-gKGllJo7sJBDS4Xl0v!_N%(yE;i4U(Ak+w| z71#&K{995iJJ*0jq2_9nc1NjSRFe|oyF~R>LG&ilp%%(r(oQY+sHVnO55>w*pq&K5 z582vLHe{J0vhejkQzj>3Rv1)ajb{!V&6b!CrhTNRbwFJMPe0*ry*m&OU1H@=(H@_{ z-<$mgpUP7x&J5lIstnZb!L_y^niW>{s~B8s4fvSmre;Nhy|{Gxtl50Q=X@pp(`jvX zdN-)j)S?@X>#x*@(a9m0fUcE;991aE<8;5Hi5`}FnWf@tUqjFC_~Vq&6Gg?5*kd}_ zGyoY%ua>NF?(y74N>y z{lK8fj)Q0;j;(n3dD3J5_?fAU4Pbvz@a zzbH$0bpEr~oj`V_FvT&G)WZ(JH2A7>+{;u8eU&)iY5`pa`JgK_DQw|aqvyb9GhgB8 zjqG^eSG}VPmBRueYdPLpOElY+?Ck!L>%$3nquxoR-~rw5+3EZn*Xexs$Y$MWZMp`h z&;sP3bDhHDQ8xB16L=ud&Nvm@5?vIhYhsa5whd$3aQ5_-=J#ss??C>gnpYZ4)Z_RH zTV{53(dqh{@Cb}NRfI#0c2!^)HOGkAM!O8d&|%VsV(eSK!a-oym&6Hcov!*M_^!=zG^b~1!btwq6|QkQyvCU1R#AIr5hSHW`Co3t}_o3zPSfR`|?Z-U;5 z^jehMjSE_=iNKI6y!I1{Yk$vP5Kwm$#{}ixOWJ!bLba1@gF5>F4_B^K}2t3YDue*^vIDz5)`$afRr29-m;YFD{PE~^rB zgGt-sD(ElJfe|g`Sz45!A*Ber5%!q0ca7vnAspv~bxFMviK^dGF2O#fq;_5$JrX{v z@Y+qZH7}Fr^fdS;w_$gnWF?i{K_#vJHNFly1a7N?X`JIx6q!lSYxfK?*B?>YMq$15B?aMrXtj+b6tPTx7eYtRt6cy&j#O=15j@SIg)udO>kZ<~4m z`GW9VPTzBQNZqQq`W0lKbgr*+BC+lbCG@VQlWa8hDX&0LW?LTQo=bT)Y)sD z-_=yt4M$nPUC?Xltt#NlO)gEnM5*dDik~+_Ny@$J;+5G;>?e=*ng#N>{nnN}i^Lo5 z+Malp*!GI*lQPeK(q3OixvK4JPt?9>Yhy1t7Hozv;vHu^YcQL~lx=1Evyn|$oEIk- zowXKU!B&lf4BxJ;!4s5WYWC6P8k4#P?`^csqG#3XdMi-gyhg(%L6hQd=rdR$i+t#VlI; z4Za{;cv3~5syU*pE-KSuv0QNwU(}pDZE92Je?z7A3SO)IJHZFzZKlR|l|NPPdSVyU zc%s%rr^?fnrvrEXmSzsTH6OBFgJLxHxc2}lbDSfaJE$kv&zG&@xQus|n(9@EIm$#{ zT0ejEGkP%c=-aftx;z8hXscSZp-kX0-|f_U*!XnU&EU4>14KEezaWm6x~g1tyZm~4 z#hr-pff(rTnlTrA#!{EMQUfc>U=N658TSB#ACL$o+h`)YYm>B%6(RVy?RM|(yT?F@W_$|JQ5Q*^b53?IfQ z6PF%Jd(VhzWo*hGg=l+B-1XKL7;ucxY*n-QzeMwYmXpRI`O(4X_HQM|6% zvfz72o~@%xa2OL@biJL`-|+~O?wBc8g88-vCvR8|7NY~pv356L5IPEMRnfy{dyWN% zBZKqv8ei2d8Lzl9Dv@!)i^qaPDdTgl`N+;%c3B$6-a{Qu-|7vJ*)=n<#EGVkbgMkp zu_FE~W_x%zHvumky39X8T@%}A!tzCCw=A{$dETO^T;`vhV%6cjotOh**&th2?)3fq z;pre^LyH>QXrH1bH`- z2Q=X*uHoIBHQy zMW+**m)Fd6)JQAI81*%N2{4KLst|loUzT6@p1Ts~R=Wd6s|l+^>rh);?J`>EMoo$- za%ToHFJpD+REBh!#_Ta@EfT*byEW4f=%)8O4fOL%@~3N|&q3D7DLGra23ni&yv z4x6vRJ=7{CdrI4Ba4e;1#H2>##Q>{0d7}2}&XJFVT`kkw?m{v2e|IsRbI;@&dtyzs zqYYO&IoZA5sAkEHqu**jkG&zcVy%4%TRjr1Zm2SKj=zD2zD+^p^w_vPtC8h&--JD@ zp|^qt9_=+1>K>hWW9`*awUq`N=hV!+vKEo6r8>%!#yQBNvIf}C)8wh98ZkYb9ZpJc zsjwDGd8vd}GP^kr(Cz8u4XbQpWYz)&wTYP^Il0CTGc4+HEO=F*uMX)j5V9n)ER9F% zC<|qvyR&rd99@BvRKF5Y52Sodhba5Wt$?OM@u9XMMN6>U-ez}HSCNH%7inwkIOhB6 zH5f^CuqN@T(ij{-w9AixLnpwxDiDKWUF8S3%Lk!6WqA8%WohZ0Ec$5{85FOv^`^T! z+U2yq(0;xqR>uX!XqV9iceR~KMfpeOLaf6%V^FNdmdtJlB_cDo&=yR#S=r>|>Z;;$ zR^E1(yCFr_d~AA52E!qaH5Tg zw3PL6@1?9GaCL3bOwn#puV9NZi~ZOUjW&APw4zOjSe~J@Wulvg%x{iQcQnJBpj3Dh zlzR3AyrVJ!4-CtnQyx|PAa4BYtWdcnKGk-uoz<_%SaK6DVu>xOc>v31PZgCbYi4d* z5nF;y%_ zU5)#hy~)$d--*$;{RWN_=wa?Bfi~!^s`lVaGSeK`fv_xn$WYrDMFUf+G-nI=c9B(U}hToU^s%)mWX6l|JBCLhF8t&NS4$ zz+Q!n*J8pn^Z~WkdBTr%%Y4{}owdvUj5ea2TDxo&C>;KlAxkm(@yGOl1fB>=V)uHi z_eU|mV4ESOwz)WR+0P$qjgjTs4V@R=`H`{CIGIcFo;=Cf*OR-bz2LU@;;Q)&aSF88 z*0jd*y}FYUsi@E{tL7@=y@vZiu_upzEWMzrk&3?efjR5gaamhT_xz4TUYdT&r$~o`2osZK1xVD(HR>i$!S3g$LcM)o}Mddmy z#JxJCYDpx$K5;Kr9bJvBNAJQ-TAxu>j;pa(=yMxZbuhVpK~?>L?|_giu^OMF!SS%3 zW~X$z3v>GRYpSUph3B%Z>iIfH`|E5+{B*TUXKjYY>G94Zy+h5p7w`_YtFy2)+Wlr2 z`Ht1CPa}nUI*{-j&j{{6n({eRDp?W7JxUsQN9hDXPrH5o6cPfas_4Da8j3%Icu|~6 zfwK%}Jk1%%q2i1`aE2Nu9?n?B89JPv_}gYmYgG-E{bJNbwYokrYOss_lqG_rc5$j4 zf}?VAN*zkUQV`1z%u8q=upT0Iwy_w4Ch zwBqUxobEseOoeK$emsEp<4(LEYtWCoQ+Bn|*^zYdDXP6mACLEOHW$&Kg36rrY&pyg zlA>f%^ih&R6z{~+PC46%{NERqtDHe1;w&o17Y~pFliJdgzWvmNCu{K$?LKOzmcD3- zUb6Ni0dw>xaoD%hoXkE|$5Q8Diw8Q3=FB-sT%~<#f^#s*jnU)iOG?J*=~ThyadMe> zDpMRY$CYIcr7CNtCOGmM*jJ3{bUpIFoX<^Hxu}EX~G~2CNpEfl8)jH6jvej ze8-l>K6ss1QLR78XidcfsCb)>E%Aj;zs@^?*{in#IH@ENWUEd@YV7^4vRTX& zQ}L1z?Up@n(EQf6h<}K_p_JWHQejO?`f>YqI%J)w#SwsxXg(vZ#)jx@9h4O-;_>`p zzF$#=4=Clqam2SeNZyJ`>a7=`k*Raz@}m%LTCpT#x-}q}7Ubcm7XoGGOZ;Hkho1Z|J z?@jkPy>N+!=7!j*Hh+366;A1#h1W(SPBY4xxMq$I+19v}^xkV4ve%}XuXH-Lkzpv- ztO4(Sbx}-7A59thTJp<6vwHR z`-faJ2M#YP={Dq$*&#l%weObag zR5`2c%oImq3gkzwaAx^1+47;HE9iJv2!k2ISyy0&iO=`{S#KC`bMa=*noUhDxE5_` zQE*Lf@zcItdFY2S+9?HiovH&}yWhdGeG^uWjZpU}FFL7JmbR@3Dow5VIv=q1v+I z%6=tO|F@$4q9{juKb>MRJQJ#;nuw`o%#&A-ODlWH(V@&Asoer)wA(If+a5IG&Xd91 z0ZWDM1KB>>5^id+n+i*ZMdO05`jDgFjviQb4Vw7~@|xjf6&%IZSNIXLqO7`I94-nf zwi2(5{M)YjhuP1cs9V%CudUrT8aYnXEzlS5E85vubh@!d69ETk@yRmW;BX+p|LE8V zJYgVY(L%_kU(?#$iEG^nT6YE6A==WxTkDE4mcydvio3OBqP_g-vc4_6wIh!-H1t-3 z@jW!*dfW%2OaeJ9+A_dX59}nfin<5uC?>YHWQjle(m^b<;YOuh1~0m15^0i$F=x|= zd@2v)ZX@HuKJ0#gOWzU9zL9wy?7kzpef#{p1;1+J=YOMh=H9%0z0tn@APv!$UccNv zm(2s+?Goy{E1STT_gPHt;>`*PFM$E^AqZQN_MMqG=&gM9h7E;Q!y77`&2iGewGDRP z8}z)U^`1A>D#m=8Gj(bfdxppKI(hr*VYbrl1)wody0@4x9+9^l7tATSAG20}K1 z9^pxZbqE^~3PSv(#XvQ}4+wtvs%iwnK!mXf=?IS@tU-7Op&a2j!X*S%ke?KW5Q#7p zVJyN71ZxoFBWytU2w^9}euQHP=Mf~0pVS5H<&+PK1L9rxEHAZX$%Bt(_2hhoBrn0zw*s z8DSLyn-VG%I!`;^7=*7LnpL{{X5qE)t5v$6**Qg}d+LuW-OX9vX^*$X7uFGo9w4c7 zIxM18gAND!10zH{5=g5Mh5`eDaRQTo8ep18&jpf(3q^dHz*R!t8d2_5U=XdO6zN#J z$#nP>NawOS?I$c5}X3phln$ zs04lMH)YEDM_LZyo!`4v2#2JAuYtl;@KR&c#4ft{#bz;2}1UX|`1(g)a<>IZ75-vXPF z9>5@vez}J6Ay4El-^=ZFY%ka62C%i9-`(Fdx9snMp8d(g{$XFJbS;3hXU|Qs7}KC4 z(Wz<1)J$M*iX}BAlk+UrG|-5Ewx(xTSOl~w#bR~Q3yi7O95ah?IhicNXk*IU3??Tp z!(^S^M{?7B8J%l2-`5{#Hd?Iaj8rS}Y}qN98S}D@X_AY}Y?y7#lL*s{nMSKoqM6{Z zVb~W#CFaMW``aB6rsJ-4POj0M0-Y#-FXSQH_vit-7Xr};U0K>a(!D_1mqRH;K_*mgZRVbB#GBu)xdA0aI_WrdTsl_48~g<}}VH6J*ch^a9#numE^AGWy-%ar1Mt zAftCG($kEl6kDcMpPG~HO3&<$D#+u)@A9gJ=D>OLnI-)o(8a zc{0pa8(N>1Vad%*Ni}8}v#t89lw4|`FMsX4j%w>1>fY-v`# z*=V(yvtcF3jE$4#OiW4|?cR6t-u8~)Rv_!o=&P>&3=(p3va&Pu)Hf^{^Qca@F?cR_ zaql!P!6OyvSt;2m^NeY~VZ2-OLD+BFm|N-g@_uIPU&)QWnV+4Kh3=k_ong(us9$6> z>rKc4L2_D()wnRj>ZupY!F0LqFz`&PVg~W1+umpQU8yWanq)*erV3+-S)~&m#U%oF^6{Y(_|t za-|F$J+mYWwt1klfvHlCWR{GeOyJA~WoGG_QXgztfSlhb3vRxYjd;3TvM)j;n=?K{ zGLdRTNPXt_&{FoVLr zPK4Dma)^9q^^X=vWZkntD>inJhi8j~9=P%Gr> z1drwf%~|05j)Ffx#A8H!gor1IG7|+qQQ#CIKUvhBDfn5`PiQ`eK=TZ<(6vD5S}5=_ z!7mbWmWlGTZlXKFiz5EA(BoB6&+CG}Md-C(q<aFm7t&V zpjU!c3;GWp^iv-6Di8W;5BiTD^fMmxW`&#n&`mR)l)UY%?};9azur(osRkp`Es&E=e3VM_Ja*n; zo2k5+ap!rJjl83>`3S@{f#+qVJ8B2xfVO(qd`D#$GR;$DEB5_Oy-|-x`E0~&NXOYh z&Xb1JygSwfWg*YTtY?KKggrtq@1xMMvs)lIW;CXHz6l8BQ+lti350& z(VUf$okA!6c%wBvCynwZ;fCXk!#IW_SP=>k=EHuyq%rKAyNJzXMo8mm{=!DqgVIEq zpM>)-|6TbC$6ACN2-4T^MIopWGzdC`Fa$k9H-!EO(Fkz}NeELBW+2Q#NJB_R$VA9R zup%r(Sd37Bungfzgf$53Mg9#4n-I1llpyRwIE+w>a2BB+;R=HE4SY8UK0;?b=xzv+ z2m=wK5#kUM5T+ueBP>LC9AO>8CWI1%!wAO^P9vN}xPov4K~;_RB7`D@BSawdMCgw& zvKlh0p>H+Mp9@@!@HoO6gpCNFB2-pGZZ+gmJ_NNL`XP)&NVH{3@j2O266SVO;8RFS zw@D9}Go-{6tAw<)lza*43@MKV1m(--ltlT>f~0bcLRp(x@W!NMOAi?5O7SUX^dGYn z5B3;aHbSNpW1A->8gr%baBPgrSs;xxrc!=fB;->WGb1F_PcwEP%4cAFQh7Exg$$Ms zIW~(`B3bDCbB&mnk<1)WB-h0v`7#|7kNF=$eEhv>Y4_$cIcfOy)W_qeCn6s|DK2hs zR@PuXQ%Pjw9c9>Y1#L&16q$l;8jGic13R!|Ci1hRkSNE_`m7pO-ZReSSY!^9ha8?f zF5B$p$o076tUi{@%^L%XbbSEQ=2G2=o2mWmEX(8hEFW|fm`Ultc_b6%a><@_tOt&R z?hDA4bas&C+nCgRxgN8dBiD)R7r9={U*tO3uH^Ny{Gx7l^hAxa4(z~buVXri7^LhQC`Cm`W_T$B$UgjW|$Qg&f!H}MXEoLhG7|+fX zlc4kefBK*Ob(8<}ckmY{>3;QZ*=_#3a};{~`P|{3XZgoG{uFokC(1(q|Mg!%;bTS1 zmjCYekFR(FpVs-qQ>&i-<1?$DeeO?dp8xaObuYa5()ySG^2)2P{q^+?Z@l@|#<$;j zchh_Cf3W$(kG5?6c-tqRezyJdlF}VzJ9q8gQ(m$6i+x}2KTuh9@X+C}zW%1#e&pz} zn&T&GPkwvq^mk{zchvphJbUi^h5Cz^E?@cE)rQ7v*MGe6)6FKyN1;^t`uVE^0)sTc zAzEFt=68j*XxS>Pb(^-~?b>(HckI+TqD$AiyLG>(N6%ip?~Ux!w_pDO_uW5m(BL8P zI~k%==ECW3nwOq2|DnvR?3~<(%@(U|LEggrMbl?s&B>f!PJd+al1G>Rr`!LZuK!=Q zf6VX^BV!*J6*qd!gJa{zjmL9siAj?tPnnuLjobg1)Bh{%??b+#GyGoDLZFhy1W-ly z0D-=AFAL~L_ttdU(>=B`{GQuZU?ANS1P0N)E}(|)p#g*G9^V;$Pp%fI1v-E< zhp#`w?~yeEY3?q4uhQKGPy<70o)2t6z9e8vI#vV2=$;O+HQh7)p5L<@_&vYJ77Yxi zbKdv--eUr=J>4?|b|4=qP*3;nfE}sbz)sX|U}tJKFoN0*>_R>#U{`8C@NQ~9usgLM zcn`H7*n`>+>`Cnh_M-L!@1^zw@1ynu@2B(s_M`mfI1*`xNu-I6~8WP4zvRA0(JvG6xbiw0vHW!2^T@P6Pr;6UI8;2_{; z;9y`0a0qZ8a2T)}XaJrDMg!}CF~A$Z5kR#Q{RXH9#sYf+9{>&nj-veo91ToxqW_TH zfe!-Hfn&-3PV^(%-%j)+>JPvK>JPw))E|J8sUHBRP(N^@KaqY;^e3_(@FCjoz)aE$ zSV(%EMgLOcUOZ3*q-$`0pdRr6HS`1q0tW&$YUl~115N_)E;aN7hEh3TOQ03l23P=W zr-pvOo@(d^9HNF^z+u30;0WMh;6rNYMS5tU7wG|1pMxI2P+$O14-C{mAD{*}5ZFco zeSkwW&;$6826_N}bl9Ij6>u5J0j?rBz;z@CxPjyVHRUAGnF~ z13#sFz;en5tfhQ<^ef5-yg~VZ>I+B*h5~&epa(Dj7zqpn4yANp9Hn=IK9t@K`cOJB zm-s!Q5AlJI6Cb#m_>mZ�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 Date: Thu, 25 Nov 2021 18:22:50 +0300 Subject: [PATCH 14/24] fix sharded client current user (#1947) --- src/Discord.Net.WebSocket/DiscordShardedClient.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Discord.Net.WebSocket/DiscordShardedClient.cs b/src/Discord.Net.WebSocket/DiscordShardedClient.cs index 307f9a009..1e71ce853 100644 --- a/src/Discord.Net.WebSocket/DiscordShardedClient.cs +++ b/src/Discord.Net.WebSocket/DiscordShardedClient.cs @@ -495,9 +495,12 @@ private void RegisterEvents(DiscordSocketClient client, bool isPrimary) client.GuildScheduledEventUserAdd += (arg1, arg2) => _guildScheduledEventUserAdd.InvokeAsync(arg1, arg2); client.GuildScheduledEventUserRemove += (arg1, arg2) => _guildScheduledEventUserRemove.InvokeAsync(arg1, arg2); } -#endregion + #endregion #region IDiscordClient + /// + ISelfUser IDiscordClient.CurrentUser => CurrentUser; + /// async Task IDiscordClient.GetApplicationInfoAsync(RequestOptions options) => await GetApplicationInfoAsync().ConfigureAwait(false); From 143ca6db437ac18d4615c0752e00464b566f6264 Mon Sep 17 00:00:00 2001 From: Quin Lynch <49576606+quinchs@users.noreply.github.com> Date: Thu, 25 Nov 2021 11:23:33 -0400 Subject: [PATCH 15/24] fix NRE when adding parameters thru builders (#1946) --- src/Discord.Net.Commands/Builders/ParameterBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Discord.Net.Commands/Builders/ParameterBuilder.cs b/src/Discord.Net.Commands/Builders/ParameterBuilder.cs index 9ee1a748c..afe3a5af6 100644 --- a/src/Discord.Net.Commands/Builders/ParameterBuilder.cs +++ b/src/Discord.Net.Commands/Builders/ParameterBuilder.cs @@ -54,7 +54,7 @@ internal void SetType(Type type) if (type.GetTypeInfo().IsValueType) DefaultValue = Activator.CreateInstance(type); else if (type.IsArray) - type = ParameterType.GetElementType(); + DefaultValue = Array.CreateInstance(type.GetElementType(), 0); ParameterType = type; } From 10afd96e6ec6dcb2bba8c1f5d54a696f60bac989 Mon Sep 17 00:00:00 2001 From: Quin Lynch <49576606+quinchs@users.noreply.github.com> Date: Thu, 25 Nov 2021 11:24:44 -0400 Subject: [PATCH 16/24] feature: Handle bidirectional usernames (#1943) * Initial implementation * Update summary --- src/Discord.Net.Core/Format.cs | 10 ++++++++++ src/Discord.Net.Rest/Entities/Users/RestUser.cs | 4 ++-- src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs | 4 ++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Discord.Net.Core/Format.cs b/src/Discord.Net.Core/Format.cs index 63f9d15a6..73be20108 100644 --- a/src/Discord.Net.Core/Format.cs +++ b/src/Discord.Net.Core/Format.cs @@ -104,5 +104,15 @@ public static string StripMarkDown(string text) var newText = Regex.Replace(text, @"(\*|_|`|~|>|\\)", ""); return newText; } + + /// + /// Formats a user's username + discriminator while maintaining bidirectional unicode + /// + /// The user whos username and discriminator to format + /// The username + discriminator + public static string UsernameAndDiscriminator(IUser user) + { + return $"\u2066{user.Username}\u2069#{user.Discriminator}"; + } } } diff --git a/src/Discord.Net.Rest/Entities/Users/RestUser.cs b/src/Discord.Net.Rest/Entities/Users/RestUser.cs index 872bab392..9cf42814c 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestUser.cs @@ -128,8 +128,8 @@ public string GetDefaultAvatarUrl() /// /// A string that resolves to Username#Discriminator of the user. /// - public override string ToString() => $"{Username}#{Discriminator}"; - private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")})"; + public override string ToString() => Format.UsernameAndDiscriminator(this); + private string DebuggerDisplay => $"{Format.UsernameAndDiscriminator(this)} ({Id}{(IsBot ? ", Bot" : "")})"; #endregion #region IUser diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs index 025daf29a..5e5e5cf0c 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs @@ -109,8 +109,8 @@ public string GetDefaultAvatarUrl() /// /// The full name of the user. /// - public override string ToString() => $"{Username}#{Discriminator}"; - private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")})"; + public override string ToString() => Format.UsernameAndDiscriminator(this); + private string DebuggerDisplay => $"{Format.UsernameAndDiscriminator(this)} ({Id}{(IsBot ? ", Bot" : "")})"; internal SocketUser Clone() => MemberwiseClone() as SocketUser; } } From 9d6dc6279db499c48811e80e9c385f7015d00333 Mon Sep 17 00:00:00 2001 From: Quin Lynch <49576606+quinchs@users.noreply.github.com> Date: Thu, 25 Nov 2021 11:25:19 -0400 Subject: [PATCH 17/24] Update socket presence and add new presence event (#1945) --- .../Entities/Users/IPresence.cs | 6 ++-- .../Entities/Users/RestUser.cs | 5 ++-- .../BaseSocketClient.Events.cs | 12 ++++++++ .../DiscordSocketClient.cs | 23 +++++++-------- .../Entities/Users/SocketGlobalUser.cs | 6 ---- .../Entities/Users/SocketGuildUser.cs | 10 +++++-- .../Entities/Users/SocketPresence.cs | 29 +++++++++++++------ .../Entities/Users/SocketUser.cs | 10 +++++-- 8 files changed, 64 insertions(+), 37 deletions(-) diff --git a/src/Discord.Net.Core/Entities/Users/IPresence.cs b/src/Discord.Net.Core/Entities/Users/IPresence.cs index 6972037f0..45babf481 100644 --- a/src/Discord.Net.Core/Entities/Users/IPresence.cs +++ b/src/Discord.Net.Core/Entities/Users/IPresence.cs @@ -1,4 +1,4 @@ -using System.Collections.Immutable; +using System.Collections.Generic; namespace Discord { @@ -14,10 +14,10 @@ public interface IPresence /// /// Gets the set of clients where this user is currently active. /// - IImmutableSet ActiveClients { get; } + IReadOnlyCollection ActiveClients { get; } /// /// Gets the list of activities that this user currently has available. /// - IImmutableList Activities { get; } + IReadOnlyCollection Activities { get; } } } diff --git a/src/Discord.Net.Rest/Entities/Users/RestUser.cs b/src/Discord.Net.Rest/Entities/Users/RestUser.cs index 9cf42814c..70f990fe7 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestUser.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Model = Discord.API.User; using EventUserModel = Discord.API.GuildScheduledEventUser; +using System.Collections.Generic; namespace Discord.Rest { @@ -41,9 +42,9 @@ public class RestUser : RestEntity, IUser, IUpdateable /// public virtual UserStatus Status => UserStatus.Offline; /// - public virtual IImmutableSet ActiveClients => ImmutableHashSet.Empty; + public virtual IReadOnlyCollection ActiveClients => ImmutableHashSet.Empty; /// - public virtual IImmutableList Activities => ImmutableList.Empty; + public virtual IReadOnlyCollection Activities => ImmutableList.Empty; /// public virtual bool IsWebhook => false; diff --git a/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs b/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs index 4ad25d4d5..91fb24021 100644 --- a/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs +++ b/src/Discord.Net.WebSocket/BaseSocketClient.Events.cs @@ -502,6 +502,18 @@ public event Func RecipientRemoved internal readonly AsyncEvent> _recipientRemovedEvent = new AsyncEvent>(); #endregion + #region Presence + + /// Fired when a users presence is updated. + public event Func PresenceUpdated + { + add { _presenceUpdated.Add(value); } + remove { _presenceUpdated.Remove(value); } + } + internal readonly AsyncEvent> _presenceUpdated = new AsyncEvent>(); + + #endregion + #region Invites /// /// Fired when an invite is created. diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs index 03c85ffc7..444e69a26 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs @@ -1858,6 +1858,8 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty var data = (payload as JToken).ToObject(_serializer); + SocketUser user = null; + if (data.GuildId.IsSpecified) { var guild = State.GetGuild(data.GuildId.Value); @@ -1872,7 +1874,7 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty return; } - var user = guild.GetUser(data.User.Id); + user = guild.GetUser(data.User.Id); if (user == null) { if (data.Status == UserStatus.Offline) @@ -1890,26 +1892,21 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty await TimedInvokeAsync(_userUpdatedEvent, nameof(UserUpdated), globalBefore, user).ConfigureAwait(false); } } - - var before = user.Clone(); - user.Update(State, data, true); - var cacheableBefore = new Cacheable(before, user.Id, true, () => Task.FromResult(user)); - await TimedInvokeAsync(_guildMemberUpdatedEvent, nameof(GuildMemberUpdated), cacheableBefore, user).ConfigureAwait(false); } else { - var globalUser = State.GetUser(data.User.Id); - if (globalUser == null) + user = State.GetUser(data.User.Id); + if (user == null) { await UnknownGlobalUserAsync(type, data.User.Id).ConfigureAwait(false); return; } - - var before = globalUser.Clone(); - globalUser.Update(State, data.User); - globalUser.Update(State, data); - await TimedInvokeAsync(_userUpdatedEvent, nameof(UserUpdated), before, globalUser).ConfigureAwait(false); } + + var before = user.Presence.Clone(); + user.Update(State, data.User); + user.Update(data); + await TimedInvokeAsync(_presenceUpdated, nameof(PresenceUpdated), user, before, user.Presence).ConfigureAwait(false); } break; case "TYPING_START": diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs index 3a1ad23b6..525ae0b34 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs @@ -1,7 +1,6 @@ using System.Diagnostics; using System.Linq; using Model = Discord.API.User; -using PresenceModel = Discord.API.Presence; namespace Discord.WebSocket { @@ -48,11 +47,6 @@ internal void RemoveRef(DiscordSocketClient discord) } } - internal void Update(ClientState state, PresenceModel model) - { - Presence = SocketPresence.Create(model); - } - private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")}, Global)"; internal new SocketGlobalUser Clone() => MemberwiseClone() as SocketGlobalUser; } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs index 147456cb0..ae3319227 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs @@ -164,8 +164,7 @@ internal void Update(ClientState state, PresenceModel model, bool updatePresence { if (updatePresence) { - Presence = SocketPresence.Create(model); - GlobalUser.Update(state, model); + Update(model); } if (model.Nick.IsSpecified) Nickname = model.Nick.Value; @@ -174,6 +173,13 @@ internal void Update(ClientState state, PresenceModel model, bool updatePresence if (model.PremiumSince.IsSpecified) _premiumSinceTicks = model.PremiumSince.Value?.UtcTicks; } + + internal override void Update(PresenceModel model) + { + Presence.Update(model); + GlobalUser.Update(model); + } + private void UpdateRoles(ulong[] roleIds) { var roles = ImmutableArray.CreateBuilder(roleIds.Length + 1); diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketPresence.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketPresence.cs index fe672a4d6..5250e15ad 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketPresence.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketPresence.cs @@ -11,26 +11,37 @@ namespace Discord.WebSocket /// Represents the WebSocket user's presence status. This may include their online status and their activity. /// [DebuggerDisplay(@"{DebuggerDisplay,nq}")] - public struct SocketPresence : IPresence + public class SocketPresence : IPresence { /// - public UserStatus Status { get; } + public UserStatus Status { get; private set; } /// - public IImmutableSet ActiveClients { get; } + public IReadOnlyCollection ActiveClients { get; private set; } /// - public IImmutableList Activities { get; } + public IReadOnlyCollection Activities { get; private set; } + + internal SocketPresence() { } internal SocketPresence(UserStatus status, IImmutableSet activeClients, IImmutableList activities) { Status = status; ActiveClients = activeClients ?? ImmutableHashSet.Empty; Activities = activities ?? ImmutableList.Empty; } + internal static SocketPresence Create(Model model) { - var clients = ConvertClientTypesDict(model.ClientStatus.GetValueOrDefault()); - var activities = ConvertActivitiesList(model.Activities); - return new SocketPresence(model.Status, clients, activities); + var entity = new SocketPresence(); + entity.Update(model); + return entity; + } + + internal void Update(Model model) + { + Status = model.Status; + ActiveClients = ConvertClientTypesDict(model.ClientStatus.GetValueOrDefault()) ?? ImmutableArray.Empty; + Activities = ConvertActivitiesList(model.Activities) ?? ImmutableArray.Empty; } + /// /// Creates a new containing all of the client types /// where a user is active from the data supplied in the Presence update frame. @@ -42,7 +53,7 @@ internal static SocketPresence Create(Model model) /// /// A collection of all s that this user is active. /// - private static IImmutableSet ConvertClientTypesDict(IDictionary clientTypesDict) + private static IReadOnlyCollection ConvertClientTypesDict(IDictionary clientTypesDict) { if (clientTypesDict == null || clientTypesDict.Count == 0) return ImmutableHashSet.Empty; @@ -84,6 +95,6 @@ private static IImmutableList ConvertActivitiesList(IList a public override string ToString() => Status.ToString(); private string DebuggerDisplay => $"{Status}{(Activities?.FirstOrDefault()?.Name ?? "")}"; - internal SocketPresence Clone() => this; + internal SocketPresence Clone() => MemberwiseClone() as SocketPresence; } } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs index 5e5e5cf0c..b38bd8a4a 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Discord.Rest; using Model = Discord.API.User; +using PresenceModel = Discord.API.Presence; namespace Discord.WebSocket { @@ -40,9 +41,9 @@ public abstract class SocketUser : SocketEntity, IUser /// public UserStatus Status => Presence.Status; /// - public IImmutableSet ActiveClients => Presence.ActiveClients ?? ImmutableHashSet.Empty; + public IReadOnlyCollection ActiveClients => Presence.ActiveClients ?? ImmutableHashSet.Empty; /// - public IImmutableList Activities => Presence.Activities ?? ImmutableList.Empty; + public IReadOnlyCollection Activities => Presence.Activities ?? ImmutableList.Empty; /// /// Gets mutual guilds shared with this user. /// @@ -91,6 +92,11 @@ internal virtual bool Update(ClientState state, Model model) return hasChanges; } + internal virtual void Update(PresenceModel model) + { + Presence.Update(model); + } + /// public async Task CreateDMChannelAsync(RequestOptions options = null) => await UserHelper.CreateDMChannelAsync(this, Discord, options).ConfigureAwait(false); From d1b31c8f529033afda8d4a9e320788de0d034693 Mon Sep 17 00:00:00 2001 From: roridev Date: Thu, 25 Nov 2021 15:31:48 -0300 Subject: [PATCH 18/24] Add `MatchResult` --- .../Results/MatchResult.cs | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/Discord.Net.Commands/Results/MatchResult.cs diff --git a/src/Discord.Net.Commands/Results/MatchResult.cs b/src/Discord.Net.Commands/Results/MatchResult.cs new file mode 100644 index 000000000..fb266efa6 --- /dev/null +++ b/src/Discord.Net.Commands/Results/MatchResult.cs @@ -0,0 +1,47 @@ +using System; + +namespace Discord.Commands +{ + public class MatchResult : IResult + { + /// + /// Gets the command that may have matched during the command execution. + /// + public CommandMatch? Match { get; } + + /// + /// Gets on which pipeline stage the command may have matched or failed. + /// + public IResult? Pipeline { get; } + + /// + public CommandError? Error { get; } + /// + public string ErrorReason { get; } + /// + public bool IsSuccess => !Error.HasValue; + + private MatchResult(CommandMatch? match, IResult? pipeline, CommandError? error, string errorReason) + { + Match = match; + Error = error; + Pipeline = pipeline; + ErrorReason = errorReason; + } + + public static MatchResult FromSuccess(CommandMatch match, IResult pipeline) + => new MatchResult(match,pipeline,null, null); + public static MatchResult FromError(CommandError error, string reason) + => new MatchResult(null,null,error, reason); + public static MatchResult FromError(Exception ex) + => FromError(CommandError.Exception, ex.Message); + public static MatchResult FromError(IResult result) + => new MatchResult(null, null,result.Error, result.ErrorReason); + public static MatchResult FromError(IResult pipeline, CommandError error, string reason) + => new MatchResult(null, pipeline, error, reason); + + public override string ToString() => IsSuccess ? "Success" : $"{Error}: {ErrorReason}"; + private string DebuggerDisplay => IsSuccess ? "Success" : $"{Error}: {ErrorReason}"; + + } +} From a92ec56d884ffe41f74c1f6b9541c1d70d6d823d Mon Sep 17 00:00:00 2001 From: roridev Date: Thu, 25 Nov 2021 16:42:18 -0300 Subject: [PATCH 19/24] Add requested changes Changes: - Use IResult instead of Optional CommandMatch - Rework branching workflow --- src/Discord.Net.Commands/CommandService.cs | 55 ++++++++++++++-------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index f54072811..18f553559 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -507,27 +507,44 @@ public async Task ExecuteAsync(ICommandContext context, string input, I var searchResult = Search(input); - //Since ValidateAndGetBestMatch is deterministic on the return type, we can use pattern matching on the type for infering the code flow. - var (validationResult, commandMatch) = await ValidateAndGetBestMatch(searchResult, context, services, multiMatchHandling); + var validationResult = await ValidateAndGetBestMatch(searchResult, context, services, multiMatchHandling); - if(validationResult is SearchResult) + if (validationResult is SearchResult result) { - await _commandExecutedEvent.InvokeAsync(Optional.Create(), context, searchResult).ConfigureAwait(false); - } - else if(validationResult is ParseResult parseResult) - { - var result = await commandMatch.Value.Command.ExecuteAsync(context, parseResult, services).ConfigureAwait(false); - if (!result.IsSuccess && !(result is RuntimeResult || result is ExecuteResult)) // succesful results raise the event in CommandInfo#ExecuteInternalAsync (have to raise it there b/c deffered execution) - await _commandExecutedEvent.InvokeAsync(commandMatch.Value.Command, context, result); + await _commandExecutedEvent.InvokeAsync(Optional.Create(), context, result).ConfigureAwait(false); return result; } - else + + if (validationResult is MatchResult matchResult) { - await _commandExecutedEvent.InvokeAsync(commandMatch.Value.Command, context, validationResult).ConfigureAwait(false); + return await handleCommandPipeline(matchResult, context, services); } + return validationResult; } + private async Task handleCommandPipeline(MatchResult matchResult, ICommandContext context, IServiceProvider services) + { + if (!matchResult.IsSuccess) + return matchResult; + + if (matchResult.Pipeline is ParseResult parseResult) + { + var executeResult = await matchResult.Match.Value.ExecuteAsync(context, parseResult, services); + + if (!executeResult.IsSuccess && !(executeResult is RuntimeResult || executeResult is ExecuteResult)) // succesful results raise the event in CommandInfo#ExecuteInternalAsync (have to raise it there b/c deffered execution) + await _commandExecutedEvent.InvokeAsync(matchResult.Match.Value.Command, context, executeResult); + return executeResult; + } + + if (matchResult.Pipeline is PreconditionResult preconditionResult) + { + await _commandExecutedEvent.InvokeAsync(matchResult.Match.Value.Command, context, preconditionResult).ConfigureAwait(false); + } + + return matchResult; + } + // Calculates the 'score' of a command given a parse result float CalculateScore(CommandMatch match, ParseResult parseResult) { @@ -554,11 +571,11 @@ float CalculateScore(CommandMatch match, ParseResult parseResult) /// The service provider to be used on the command's dependency injection. /// The handling mode when multiple command matches are found. /// A task that represents the asynchronous validation operation. The task result contains the result of the - /// command validation and the command matched, if a match was found. - public async Task<(IResult, Optional)> ValidateAndGetBestMatch(SearchResult matches, ICommandContext context, IServiceProvider provider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception) + /// command validation as a or a if no matches were found. + public async Task ValidateAndGetBestMatch(SearchResult matches, ICommandContext context, IServiceProvider provider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception) { if (!matches.IsSuccess) - return (matches, Optional.Create()); + return matches; var commands = matches.Commands; var preconditionResults = new Dictionary(); @@ -574,11 +591,11 @@ float CalculateScore(CommandMatch match, ParseResult parseResult) if (successfulPreconditions.Length == 0) { + //All preconditions failed, return the one from the highest priority command var bestCandidate = preconditionResults .OrderByDescending(x => x.Key.Command.Priority) .FirstOrDefault(x => !x.Value.IsSuccess); - - return (bestCandidate.Value, bestCandidate.Key); + return MatchResult.FromSuccess(bestCandidate.Key,bestCandidate.Value); } var parseResults = new Dictionary(); @@ -615,12 +632,12 @@ float CalculateScore(CommandMatch match, ParseResult parseResult) var bestMatch = parseResults .FirstOrDefault(x => !x.Value.IsSuccess); - return (bestMatch.Value, bestMatch.Key); + return MatchResult.FromSuccess(bestMatch.Key,bestMatch.Value); } var chosenOverload = successfulParses[0]; - return (chosenOverload.Value, chosenOverload.Key); + return MatchResult.FromSuccess(chosenOverload.Key,chosenOverload.Value); } protected virtual void Dispose(bool disposing) From adf3a9c459958254cd7241acf27a8c2afbeea822 Mon Sep 17 00:00:00 2001 From: roridev Date: Fri, 26 Nov 2021 09:26:53 -0300 Subject: [PATCH 20/24] Fix incorrect casing on `HandleCommandPipeline` --- src/Discord.Net.Commands/CommandService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index 18f553559..7d03c4059 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -517,13 +517,13 @@ public async Task ExecuteAsync(ICommandContext context, string input, I if (validationResult is MatchResult matchResult) { - return await handleCommandPipeline(matchResult, context, services); + return await HandleCommandPipeline(matchResult, context, services); } return validationResult; } - private async Task handleCommandPipeline(MatchResult matchResult, ICommandContext context, IServiceProvider services) + private async Task HandleCommandPipeline(MatchResult matchResult, ICommandContext context, IServiceProvider services) { if (!matchResult.IsSuccess) return matchResult; From 82276e351aa306920e6a0ea7535c81428dd2003c Mon Sep 17 00:00:00 2001 From: Quin Lynch <49576606+quinchs@users.noreply.github.com> Date: Fri, 26 Nov 2021 11:29:53 -0400 Subject: [PATCH 21/24] feature: default application games (#1949) * Initial implementation * Add missing summary --- src/Discord.Net.Core/Discord.Net.Core.csproj | 2 +- .../Activities/DefaultApplications.cs | 86 +++++++++++++++++++ .../Entities/Channels/INestedChannel.cs | 22 +++-- .../Entities/Channels/RestTextChannel.cs | 7 +- .../Entities/Channels/RestVoiceChannel.cs | 3 + .../Entities/Channels/SocketTextChannel.cs | 3 + .../Entities/Channels/SocketVoiceChannel.cs | 3 + .../MockedEntities/MockedTextChannel.cs | 1 + .../MockedEntities/MockedVoiceChannel.cs | 1 + 9 files changed, 118 insertions(+), 10 deletions(-) create mode 100644 src/Discord.Net.Core/Entities/Activities/DefaultApplications.cs diff --git a/src/Discord.Net.Core/Discord.Net.Core.csproj b/src/Discord.Net.Core/Discord.Net.Core.csproj index 29868e1c7..7dc55b1cf 100644 --- a/src/Discord.Net.Core/Discord.Net.Core.csproj +++ b/src/Discord.Net.Core/Discord.Net.Core.csproj @@ -1,6 +1,6 @@  - + Discord.Net.Core Discord diff --git a/src/Discord.Net.Core/Entities/Activities/DefaultApplications.cs b/src/Discord.Net.Core/Entities/Activities/DefaultApplications.cs new file mode 100644 index 000000000..80f128fa8 --- /dev/null +++ b/src/Discord.Net.Core/Entities/Activities/DefaultApplications.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord +{ + public enum DefaultApplications : ulong + { + /// + /// Watch youtube together. + /// + Youtube = 880218394199220334, + + /// + /// Youtube development application. + /// + YoutubeDev = 880218832743055411, + + /// + /// Poker! + /// + Poker = 755827207812677713, + + /// + /// Betrayal: A Party Adventure. Betrayal is a social deduction game inspired by Werewolf, Town of Salem, and Among Us. + /// + Betrayal = 773336526917861400, + + /// + /// Sit back, relax, and do some fishing! + /// + Fishing = 814288819477020702, + + /// + /// The queens gambit. + /// + Chess = 832012774040141894, + + /// + /// Development version of chess. + /// + ChessDev = 832012586023256104, + + /// + /// LetterTile is a version of scrabble. + /// + LetterTile = 879863686565621790, + + /// + /// Find words in a jumble of letters in coffee. + /// + WordSnack = 879863976006127627, + + /// + /// It's like skribbl.io. + /// + DoodleCrew = 878067389634314250, + + /// + /// It's like cards against humanity. + /// + Awkword = 879863881349087252, + + /// + /// A word-search like game where you unscramble words and score points in a scrabble fashion. + /// + SpellCast = 852509694341283871, + + /// + /// Classic checkers + /// + Checkers = 832013003968348200, + + /// + /// The development version of poker. + /// + PokerDev = 763133495793942528, + + /// + /// SketchyArtist. + /// + SketchyArtist = 879864070101172255 + } +} diff --git a/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs b/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs index 563acd4f8..511d2bf51 100644 --- a/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs @@ -60,13 +60,6 @@ public interface INestedChannel : IGuildChannel /// /// Creates a new invite to this channel. /// - /// - /// The following example creates a new invite to this channel; the invite lasts for 12 hours and can only - /// be used 3 times throughout its lifespan. - /// - /// await guildChannel.CreateInviteAsync(maxAge: 43200, maxUses: 3); - /// - /// /// The id of the embedded application to open for this invite. /// The time (in seconds) until the invite expires. Set to null to never expire. /// The max amount of times this invite may be used. Set to null to have unlimited uses. @@ -79,6 +72,21 @@ public interface INestedChannel : IGuildChannel /// Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null); + /// + /// Creates a new invite to this channel. + /// + /// The application to open for this invite. + /// The time (in seconds) until the invite expires. Set to null to never expire. + /// The max amount of times this invite may be used. Set to null to have unlimited uses. + /// If true, the user accepting this invite will be kicked from the guild after closing their client. + /// If true, don't try to reuse a similar invite (useful for creating many unique one time use invites). + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous invite creation operation. The task result contains an invite + /// metadata object containing information for the created invite. + /// + Task CreateInviteToApplicationAsync(DefaultApplications application, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null); + /// /// Creates a new invite to this channel. /// diff --git a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs index f14bc2ecf..57de0eb45 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs @@ -227,8 +227,11 @@ public Task SyncPermissionsAsync(RequestOptions options = null) /// public virtual async Task CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); - public virtual Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) - => throw new NotImplementedException(); + public virtual async Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options); + /// + public virtual async Task CreateInviteToApplicationAsync(DefaultApplications application, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, (ulong)application, options); public virtual Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => throw new NotImplementedException(); /// diff --git a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs index 48fc11dcb..239c00467 100644 --- a/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs +++ b/src/Discord.Net.Rest/Entities/Channels/RestVoiceChannel.cs @@ -78,6 +78,9 @@ public async Task CreateInviteAsync(int? maxAge = 86400, int? m public async Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options).ConfigureAwait(false); /// + public virtual async Task CreateInviteToApplicationAsync(DefaultApplications application, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, (ulong)application, options); + /// public async Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteToStreamAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, user, options).ConfigureAwait(false); /// diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs index 8722b569d..aea1bfda5 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs @@ -324,6 +324,9 @@ public virtual async Task CreateInviteAsync(int? maxAge = 86400 public virtual async Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options).ConfigureAwait(false); /// + public virtual async Task CreateInviteToApplicationAsync(DefaultApplications application, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, (ulong)application, options); + /// public virtual async Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteToStreamAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, user, options).ConfigureAwait(false); /// diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs index e57051e80..08b976bfe 100644 --- a/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs +++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketVoiceChannel.cs @@ -100,6 +100,9 @@ public async Task CreateInviteAsync(int? maxAge = 86400, int? m public async Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, applicationId, options).ConfigureAwait(false); /// + public virtual async Task CreateInviteToApplicationAsync(DefaultApplications application, int? maxAge = 86400, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) + => await ChannelHelper.CreateInviteToApplicationAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, (ulong)application, options); + /// public async Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => await ChannelHelper.CreateInviteToStreamAsync(this, Discord, maxAge, maxUses, isTemporary, isUnique, user, options).ConfigureAwait(false); /// diff --git a/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs b/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs index 6d08a4478..ad0af04b2 100644 --- a/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs +++ b/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs @@ -214,5 +214,6 @@ IAsyncEnumerable> IChannel.GetUsersAsync(CacheMode mo public Task SendFileAsync(FileAttachment attachment, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) => throw new NotImplementedException(); public Task SendFilesAsync(IEnumerable attachments, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null, MessageComponent component = null, ISticker[] stickers = null, Embed[] embeds = null) => throw new NotImplementedException(); public Task CreateThreadAsync(string name, ThreadType type = ThreadType.PublicThread, ThreadArchiveDuration autoArchiveDuration = ThreadArchiveDuration.OneDay, IMessage message = null, bool? invitable = null, int? slowmode = null, RequestOptions options = null) => throw new NotImplementedException(); + public Task CreateInviteToApplicationAsync(DefaultApplications application, int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => throw new NotImplementedException(); } } diff --git a/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs b/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs index 61a32e391..4514dfc97 100644 --- a/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs +++ b/test/Discord.Net.Tests.Unit/MockedEntities/MockedVoiceChannel.cs @@ -50,6 +50,7 @@ public Task CreateInviteAsync(int? maxAge = 86400, int? maxUses } public Task CreateInviteToApplicationAsync(ulong applicationId, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => throw new NotImplementedException(); + public Task CreateInviteToApplicationAsync(DefaultApplications application, int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => throw new NotImplementedException(); public Task CreateInviteToStreamAsync(IUser user, int? maxAge, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null) => throw new NotImplementedException(); From 51e06e9ce190ac46aeaeb8650d71d58eba0b5412 Mon Sep 17 00:00:00 2001 From: Quin Lynch <49576606+quinchs@users.noreply.github.com> Date: Fri, 26 Nov 2021 11:30:19 -0400 Subject: [PATCH 22/24] feature: warn on invalid gateway intents (#1948) --- .../DiscordSocketClient.cs | 51 +++++++++++++++++++ .../DiscordSocketConfig.cs | 5 ++ 2 files changed, 56 insertions(+) diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs index 444e69a26..9ef827778 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs @@ -76,6 +76,7 @@ public partial class DiscordSocketClient : BaseSocketClient, IDiscordClient internal int? HandlerTimeout { get; private set; } internal bool AlwaysDownloadDefaultStickers { get; private set; } internal bool AlwaysResolveStickers { get; private set; } + internal bool LogGatewayIntentWarnings { get; private set; } internal new DiscordSocketApiClient ApiClient => base.ApiClient; /// public override IReadOnlyCollection Guilds => State.Guilds; @@ -147,6 +148,7 @@ private DiscordSocketClient(DiscordSocketConfig config, API.DiscordSocketApiClie AlwaysDownloadUsers = config.AlwaysDownloadUsers; AlwaysDownloadDefaultStickers = config.AlwaysDownloadDefaultStickers; AlwaysResolveStickers = config.AlwaysResolveStickers; + LogGatewayIntentWarnings = config.LogGatewayIntentWarnings; HandlerTimeout = config.HandlerTimeout; State = new ClientState(0, 0); Rest = new DiscordSocketRestClient(config, ApiClient); @@ -238,6 +240,9 @@ internal override async Task OnLoginAsync(TokenType tokenType, string token) _defaultStickers = builder.ToImmutable(); } + + if(LogGatewayIntentWarnings) + await LogGatewayIntentsWarning().ConfigureAwait(false); } /// @@ -708,6 +713,52 @@ await ApiClient.SendPresenceUpdateAsync( game); } + private async Task LogGatewayIntentsWarning() + { + if(_gatewayIntents.HasFlag(GatewayIntents.GuildPresences) && !_presenceUpdated.HasSubscribers) + { + await _gatewayLogger.WarningAsync("You're using the GuildPresences intent without listening to the PresenceUpdate event, consider removing the intent from your config.").ConfigureAwait(false); + } + + if(!_gatewayIntents.HasFlag(GatewayIntents.GuildPresences) && _presenceUpdated.HasSubscribers) + { + await _gatewayLogger.WarningAsync("You're using the PresenceUpdate event without specifying the GuildPresences intent, consider adding the intent to your config.").ConfigureAwait(false); + } + + bool hasGuildScheduledEventsSubscribers = + _guildScheduledEventCancelled.HasSubscribers || + _guildScheduledEventUserRemove.HasSubscribers || + _guildScheduledEventCompleted.HasSubscribers || + _guildScheduledEventCreated.HasSubscribers || + _guildScheduledEventStarted.HasSubscribers || + _guildScheduledEventUpdated.HasSubscribers || + _guildScheduledEventUserAdd.HasSubscribers; + + if(_gatewayIntents.HasFlag(GatewayIntents.GuildScheduledEvents) && !hasGuildScheduledEventsSubscribers) + { + await _gatewayLogger.WarningAsync("You're using the GuildScheduledEvents gateway intent without listening to any events related to that intent, consider removing the intent from your config.").ConfigureAwait(false); + } + + if(!_gatewayIntents.HasFlag(GatewayIntents.GuildScheduledEvents) && hasGuildScheduledEventsSubscribers) + { + await _gatewayLogger.WarningAsync("You're using events related to the GuildScheduledEvents gateway intent without specifying the intent, consider adding the intent to your config.").ConfigureAwait(false); + } + + bool hasInviteEventSubscribers = + _inviteCreatedEvent.HasSubscribers || + _inviteDeletedEvent.HasSubscribers; + + if (_gatewayIntents.HasFlag(GatewayIntents.GuildInvites) && !hasInviteEventSubscribers) + { + await _gatewayLogger.WarningAsync("You're using the GuildInvites gateway intent without listening to any events related to that intent, consider removing the intent from your config.").ConfigureAwait(false); + } + + if (!_gatewayIntents.HasFlag(GatewayIntents.GuildInvites) && hasInviteEventSubscribers) + { + await _gatewayLogger.WarningAsync("You're using events related to the GuildInvites gateway intent without specifying the intent, consider adding the intent to your config.").ConfigureAwait(false); + } + } + #region ProcessMessageAsync private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string type, object payload) { diff --git a/src/Discord.Net.WebSocket/DiscordSocketConfig.cs b/src/Discord.Net.WebSocket/DiscordSocketConfig.cs index 8615eac71..f0e6dc857 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketConfig.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketConfig.cs @@ -183,6 +183,11 @@ public int MaxWaitBetweenGuildAvailablesBeforeReady /// public GatewayIntents GatewayIntents { get; set; } = GatewayIntents.AllUnprivileged; + /// + /// Gets or sets whether or not to log warnings related to guild intents and events. + /// + public bool LogGatewayIntentWarnings { get; set; } = true; + /// /// Initializes a new instance of the class with the default configuration. /// From b9274d115dfcec28a732fd3c9122ca65ebe4951e Mon Sep 17 00:00:00 2001 From: Monica S Date: Fri, 26 Nov 2021 15:41:08 +0000 Subject: [PATCH 23/24] Add characters commonly use in links to Sanitize (#1152) Co-authored-by: Quin Lynch <49576606+quinchs@users.noreply.github.com> --- src/Discord.Net.Core/Format.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Discord.Net.Core/Format.cs b/src/Discord.Net.Core/Format.cs index 73be20108..a5951aa73 100644 --- a/src/Discord.Net.Core/Format.cs +++ b/src/Discord.Net.Core/Format.cs @@ -7,7 +7,8 @@ namespace Discord public static class Format { // Characters which need escaping - private static readonly string[] SensitiveCharacters = { "\\", "*", "_", "~", "`", "|", ">" }; + private static readonly string[] SensitiveCharacters = { + "\\", "*", "_", "~", "`", ".", ":", "/", ">", "|" }; /// Returns a markdown-formatted string with bold formatting. public static string Bold(string text) => $"**{text}**"; From 19a66bf8782e7b8879c6b8b372134e01be0090d7 Mon Sep 17 00:00:00 2001 From: Daniel Baynton <49287178+230Daniel@users.noreply.github.com> Date: Fri, 26 Nov 2021 15:41:55 +0000 Subject: [PATCH 24/24] feature: Add method to clear guild user cache (#1767) * Add method to clear a SocketGuild's user cache * Add optional predicate * Compress overload to be consistant * Fix global user not clearing (may cause other issues) * Remove debug code and add param documentation * Standardise doc string * Remove old hack-fix * Rename new method for consistency * Add missing line to reset downloaderPromise * Undo accidental whitespace changes * Rider better actually keep the tab this time Co-authored-by: Quin Lynch <49576606+quinchs@users.noreply.github.com> --- src/Discord.Net.WebSocket/ClientState.cs | 4 +-- .../Entities/Guilds/SocketGuild.cs | 31 ++++++++++++------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/Discord.Net.WebSocket/ClientState.cs b/src/Discord.Net.WebSocket/ClientState.cs index 7129feb48..c40ae3f92 100644 --- a/src/Discord.Net.WebSocket/ClientState.cs +++ b/src/Discord.Net.WebSocket/ClientState.cs @@ -115,7 +115,7 @@ internal SocketGuild RemoveGuild(ulong id) if (_guilds.TryRemove(id, out SocketGuild guild)) { guild.PurgeChannelCache(this); - guild.PurgeGuildUserCache(); + guild.PurgeUserCache(); return guild; } return null; @@ -140,7 +140,7 @@ internal SocketGlobalUser RemoveUser(ulong id) internal void PurgeUsers() { foreach (var guild in _guilds.Values) - guild.PurgeGuildUserCache(); + guild.PurgeUserCache(); } internal SocketApplicationCommand GetCommand(ulong id) diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs index 03c655a34..697d5fe82 100644 --- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -1144,22 +1144,29 @@ internal SocketGuildUser RemoveUser(ulong id) } return null; } - internal void PurgeGuildUserCache() + + /// + /// Purges this guild's user cache. + /// + public void PurgeUserCache() => PurgeUserCache(_ => true); + /// + /// Purges this guild's user cache. + /// + /// The predicate used to select which users to clear. + public void PurgeUserCache(Func predicate) { - var members = Users; - var self = CurrentUser; - _members.Clear(); - if (self != null) - _members.TryAdd(self.Id, self); + var membersToPurge = Users.Where(x => predicate.Invoke(x) && x?.Id != Discord.CurrentUser.Id); + var membersToKeep = Users.Where(x => !predicate.Invoke(x) || x?.Id == Discord.CurrentUser.Id); + + foreach (var member in membersToPurge) + if(_members.TryRemove(member.Id, out _)) + member.GlobalUser.RemoveRef(Discord); + + foreach (var member in membersToKeep) + _members.TryAdd(member.Id, member); _downloaderPromise = new TaskCompletionSource(); DownloadedMemberCount = _members.Count; - - foreach (var member in members) - { - if (member.Id != self?.Id) - member.GlobalUser.RemoveRef(Discord); - } } ///