{"TotalCount":242,"Files":[{"Ident":"brycpt.lichessnetport","Path":"API/AccountAPI.cs","FileName":"AccountAPI.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nusing LichessNET.Entities;\r\nusing LichessNET.Entities.Account;\r\nusing LichessNET.Entities.Social;\r\nusing LichessNET.Entities.Social.Timeline;\r\n\r\nnamespace LichessNET.API;\r\n\r\npublic partial class LichessApiClient\r\n{\r\n    /// \u003Csummary\u003E\r\n    ///     Retrieves the email address of the authenticated user.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Creturns\u003E\r\n    ///     A string representing the email address of the authenticated user.\r\n    /// \u003C/returns\u003E\r\n    public async Task\u003Cstring\u003E GetAccountEmail()\r\n    {\r\n        await _ratelimitController.Consume(\u0022api/account\u0022, false);\r\n\r\n        var request = GetRequestScaffold(\u0022api/account/email\u0022);\r\n\r\n        var response = await SendRequest(request);\r\n        var content = await response.Content.ReadFromJsonAsync\u003CDictionary\u003Cstring, string\u003E\u003E();\r\n        return content[\u0022email\u0022];\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    /// Retrieves the profile information of the authenticated user from the Lichess platform.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Creturns\u003E\r\n    /// An instance of \u003Csee cref=\u0022LichessUser\u0022/\u003E representing the profile details of the user.\r\n    /// \u003C/returns\u003E\r\n    public async Task\u003CLichessUser\u003E GetOwnProfile()\r\n    {\r\n        await _ratelimitController.Consume(\u0022api/account\u0022, false);\r\n\r\n        var request = GetRequestScaffold(\u0022api/account\u0022);\r\n        var response = await SendRequest(request);\r\n        return await response.Content.ReadFromJsonAsync\u003CLichessUser\u003E();\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    /// Retrieves the account preferences of the authenticated user.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Creturns\u003E\r\n    /// An instance of \u003Csee cref=\u0022AccountPreferences\u0022/\u003E representing the user\u0027s account preferences.\r\n    /// \u003C/returns\u003E\r\n    public async Task\u003CAccountPreferences\u003E GetAccountPreferences()\r\n    {\r\n        await _ratelimitController.Consume(\u0022api/account\u0022, false);\r\n\r\n        var request = GetRequestScaffold(\u0022api/account/preferences\u0022);\r\n\r\n        var response = await SendRequest(request);\r\n\r\n\r\n        var preferences = await response.Content.ReadFromJsonAsync\u003CAccountPreferences\u003E();\r\n        return preferences;\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    ///     Determines whether the authenticated user\u0027s account is in kid mode.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Creturns\u003E\r\n    ///     A boolean value indicating if the user\u0027s account is set to kid mode.\r\n    /// \u003C/returns\u003E\r\n    public async Task\u003Cbool\u003E GetKidModeStatus()\r\n    {\r\n        await _ratelimitController.Consume(\u0022api/account\u0022, false);\r\n\r\n        var request = GetRequestScaffold(\u0022api/account/kid\u0022);\r\n\r\n        var response = await SendRequest(request);\r\n        var content = await response.Content.ReadFromJsonAsync\u003CDictionary\u003Cstring, bool\u003E\u003E();\r\n        return content[\u0022kid\u0022];\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    /// Sets the kid mode status for the authenticated account.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Cparam name=\u0022enable\u0022\u003E\r\n    /// A boolean value indicating whether to enable or disable kid mode.\r\n    /// \u003C/param\u003E\r\n    /// \u003Creturns\u003E\r\n    /// A boolean indicating whether the operation was successful.\r\n    /// \u003C/returns\u003E\r\n    public async Task\u003Cbool\u003E SetKidModeStatus(bool enable)\r\n    {\r\n        var request = GetRequestScaffold(\u0022api/account/kid\u0022, Tuple.Create(\u0022v\u0022, enable.ToString()));\r\n        var response = await SendRequest(request, \u0022POST\u0022);\r\n\r\n                var result = LichessJson.Deserialize\u003CDictionary\u003Cstring, bool\u003E\u003E(await response.Content.ReadAsStringAsync());\r\n        return result != null \u0026\u0026 result.TryGetValue(\u0022ok\u0022, out var ok) \u0026\u0026 ok;\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    /// Follows a player with the specified username on Lichess.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Cparam name=\u0022username\u0022\u003E\r\n    /// The username of the player to follow.\r\n    /// \u003C/param\u003E\r\n    /// \u003Creturns\u003E\r\n    /// A boolean value indicating whether the operation was successful.\r\n    /// \u003C/returns\u003E\r\n    public async Task\u003Cbool\u003E FollowPlayerAsync(string username)\r\n    {\r\n        await _ratelimitController.Consume(\u0022api/account\u0022, false);\r\n\r\n        var request = GetRequestScaffold($\u0022api/rel/follow/{username}\u0022);\r\n        var response = await SendRequest(request, \u0022POST\u0022);\r\n        var content = await response.Content.ReadFromJsonAsync\u003CDictionary\u003Cstring, bool\u003E\u003E();\r\n        return content[\u0022ok\u0022];\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    /// Unfollows a specified player using their username.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Cparam name=\u0022username\u0022\u003E\r\n    /// The username of the player to unfollow.\r\n    /// \u003C/param\u003E\r\n    /// \u003Creturns\u003E\r\n    /// A boolean value indicating whether the operation was successful.\r\n    /// \u003C/returns\u003E\r\n    public async Task\u003Cbool\u003E UnfollowPlayerAsync(string username)\r\n    {\r\n        await _ratelimitController.Consume(\u0022api/account\u0022, false);\r\n\r\n        var request = GetRequestScaffold($\u0022api/rel/unfollow/{username}\u0022);\r\n        var response = await SendRequest(request, \u0022POST\u0022);\r\n        var content = await response.Content.ReadFromJsonAsync\u003CDictionary\u003Cstring, bool\u003E\u003E();\r\n        return content[\u0022ok\u0022];\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    /// Blocks a player on Lichess based on their username.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Cparam name=\u0022username\u0022\u003E\r\n    /// The username of the player to be blocked.\r\n    /// \u003C/param\u003E\r\n    /// \u003Creturns\u003E\r\n    /// A boolean indicating whether the player was successfully blocked.\r\n    /// \u003C/returns\u003E\r\n    public async Task\u003Cbool\u003E BlockPlayerAsync(string username)\r\n    {\r\n        await _ratelimitController.Consume(\u0022api/account\u0022, false);\r\n\r\n        var request = GetRequestScaffold($\u0022api/rel/block/{username}\u0022);\r\n        var response = await SendRequest(request, \u0022POST\u0022);\r\n        var content = await response.Content.ReadFromJsonAsync\u003CDictionary\u003Cstring, bool\u003E\u003E();\r\n        return content[\u0022ok\u0022];\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    /// Unblocks a player specified by username.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Cparam name=\u0022username\u0022\u003E\r\n    /// The username of the player to unblock.\r\n    /// \u003C/param\u003E\r\n    /// \u003Creturns\u003E\r\n    /// A boolean value indicating whether the player was successfully unblocked.\r\n    /// \u003C/returns\u003E\r\n    public async Task\u003Cbool\u003E UnblockPlayerAsync(string username)\r\n    {\r\n        await _ratelimitController.Consume(\u0022api/account\u0022, false);\r\n\r\n        var request = GetRequestScaffold($\u0022api/rel/unblock/{username}\u0022);\r\n        var response = await SendRequest(request, \u0022POST\u0022);\r\n        var content = await response.Content.ReadFromJsonAsync\u003CDictionary\u003Cstring, bool\u003E\u003E();\r\n        return content[\u0022ok\u0022];\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    /// Gets the timeline of the authenticated user.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Cparam name=\u0022since\u0022\u003EWhen the timeline should start\u003C/param\u003E\r\n    /// \u003Cparam name=\u0022nb\u0022\u003EThe number of timeline events that should be loaded. Defaults to 15, the maximum is 50.\u003C/param\u003E\r\n    /// \u003Creturns\u003EA Timeline object\u003C/returns\u003E\r\n    public async Task\u003CTimeline?\u003E GetTimelineAsync(DateTime since, int nb = 15)\r\n    {\r\n        await _ratelimitController.Consume(\u0022api/timeline\u0022, false);\r\n\r\n        var unixTimestamp = new DateTimeOffset(since).ToUnixTimeMilliseconds();\r\n        var request = GetRequestScaffold($\u0022api/timeline\u0022,\r\n            new Tuple\u003Cstring, string\u003E(\u0022since\u0022, unixTimestamp.ToString()),\r\n            new Tuple\u003Cstring, string\u003E(\u0022nb\u0022, nb.ToString()));\r\n\r\n        var response = await SendRequest(request);\r\n        var content = await response.Content.ReadAsStringAsync();\r\n\r\n                var root = LichessJson.Parse(content);\r\n        var timeline = new Timeline\r\n        {\r\n            Entries = new List\u003CTimelineEntry\u003E(),\r\n            Users = root.TryGetProperty(\u0022users\u0022, out var users)\r\n                ? users.Deserialize\u003CDictionary\u003Cstring, TimelineUser\u003E\u003E(LichessJson.Options) ?? new Dictionary\u003Cstring, TimelineUser\u003E()\r\n                : new Dictionary\u003Cstring, TimelineUser\u003E()\r\n        };\r\n\r\n        if (root.TryGetProperty(\u0022entries\u0022, out var entries))\r\n        {\r\n            foreach (var entryElement in entries.EnumerateArray())\r\n            {\r\n                var type = entryElement.TryGetProperty(\u0022type\u0022, out var typeElement) ? typeElement.GetString() : null;\r\n                var date = entryElement.TryGetProperty(\u0022date\u0022, out var dateElement) ? dateElement.GetInt64() : 0;\r\n                var data = entryElement.TryGetProperty(\u0022data\u0022, out var dataElement)\r\n                    ? TimelineEventDataConverter.DeserializeData(type, dataElement, LichessJson.Options)\r\n                    : new UnknownEventData();\r\n\r\n                timeline.Entries.Add(new TimelineEntry\r\n                {\r\n                    Type = type,\r\n                    Date = date,\r\n                    Data = data\r\n                });\r\n            }\r\n        }\r\n\r\n        return timeline;\r\n    }\r\n}\r\n\r\n\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Code/Entities/Enumerations/Speed.cs","FileName":"Speed.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nnamespace LichessNET.Entities.Enumerations;\r\n\r\npublic enum Speed\r\n{\r\n    UltraBullet, \r\n    Bullet,\r\n    Blitz,\r\n    Rapid,\r\n    Classical,\r\n    Correspondence,\r\n}\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Code/Entities/Social/Timeline/TimelineEventData.cs","FileName":"TimelineEventData.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nnamespace LichessNET.Entities.Social.Timeline\r\n{\r\n    public abstract class TimelineEventData\r\n    {\r\n    }\r\n\r\n    public class FollowEventData : TimelineEventData\r\n    {\r\n        public string U1 { get; set; }\r\n        public string U2 { get; set; }\r\n    }\r\n\r\n    public class UnknownEventData : TimelineEventData\r\n    {\r\n    }\r\n\r\n    public class TeamJoinEventData : TimelineEventData\r\n    {\r\n        public string UserId { get; set; }\r\n        public string TeamId { get; set; }\r\n    }\r\n\r\n    public class TeamCreateEventData : TimelineEventData\r\n    {\r\n        public string UserId { get; set; }\r\n        public string TeamId { get; set; }\r\n    }\r\n\r\n    public class ForumPostEventData : TimelineEventData\r\n    {\r\n        public string UserId { get; set; }\r\n        public string TopicId { get; set; }\r\n        public string TopicName { get; set; }\r\n        public string PostId { get; set; }\r\n    }\r\n\r\n    public class UblogPostEventData : TimelineEventData\r\n    {\r\n        public string UserId { get; set; }\r\n        public string Id { get; set; }\r\n        public string Slug { get; set; }\r\n        public string Title { get; set; }\r\n    }\r\n\r\n    public class TourJoinEventData : TimelineEventData\r\n    {\r\n        public string UserId { get; set; }\r\n        public string TourId { get; set; }\r\n        public string TourName { get; set; }\r\n    }\r\n\r\n    public class GameEndEventData : TimelineEventData\r\n    {\r\n        public string FullId { get; set; }\r\n        public string Perf { get; set; }\r\n        public string Opponent { get; set; }\r\n        public bool Win { get; set; }\r\n    }\r\n\r\n    public class SimulCreateEventData : TimelineEventData\r\n    {\r\n        public string UserId { get; set; }\r\n        public string SimulId { get; set; }\r\n        public string SimulName { get; set; }\r\n    }\r\n\r\n    public class SimulJoinEventData : TimelineEventData\r\n    {\r\n        public string UserId { get; set; }\r\n        public string SimulId { get; set; }\r\n        public string SimulName { get; set; }\r\n    }\r\n\r\n    public class StudyLikeEventData : TimelineEventData\r\n    {\r\n        public string UserId { get; set; }\r\n        public string StudyId { get; set; }\r\n        public string StudyName { get; set; }\r\n    }\r\n\r\n    public class PlanStartEventData : TimelineEventData\r\n    {\r\n        public string UserId { get; set; }\r\n    }\r\n\r\n    public class PlanRenewEventData : TimelineEventData\r\n    {\r\n        public string UserId { get; set; }\r\n        public int Months { get; set; }\r\n    }\r\n\r\n    public class BlogPostEventData : TimelineEventData\r\n    {\r\n        public string Id { get; set; }\r\n        public string Slug { get; set; }\r\n        public string Title { get; set; }\r\n    }\r\n\r\n    public class UblogPostLikeEventData : TimelineEventData\r\n    {\r\n        public string UserId { get; set; }\r\n        public string Id { get; set; }\r\n        public string Title { get; set; }\r\n    }\r\n\r\n    public class StreamStartEventData : TimelineEventData\r\n    {\r\n        public string Id { get; set; }\r\n        public string Title { get; set; }\r\n    }\r\n}\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Code/Entities/Social/Timeline/TimelineEventDataConverter.cs","FileName":"TimelineEventDataConverter.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nnamespace LichessNET.Entities.Social.Timeline;\r\n\r\ninternal class TimelineEventDataConverter : JsonConverter\u003CTimelineEventData\u003E\r\n{\r\n    public override TimelineEventData Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\r\n    {\r\n        using var document = JsonDocument.ParseValue(ref reader);\r\n        return DeserializeData(null, document.RootElement, options);\r\n    }\r\n\r\n    public override void Write(Utf8JsonWriter writer, TimelineEventData value, JsonSerializerOptions options)\r\n    {\r\n        JsonSerializer.Serialize(writer, (object)value, options);\r\n    }\r\n\r\n    internal static TimelineEventData DeserializeData(string type, JsonElement data, JsonSerializerOptions options)\r\n    {\r\n        if (string.IsNullOrWhiteSpace(type) \u0026\u0026 data.TryGetProperty(\u0022type\u0022, out var embeddedType))\r\n            type = embeddedType.GetString();\r\n\r\n        if (data.TryGetProperty(\u0022data\u0022, out var nestedData))\r\n            data = nestedData;\r\n\r\n                TimelineEventData result = type switch\r\n        {\r\n            \u0022follow\u0022 =\u003E data.Deserialize\u003CFollowEventData\u003E(options),\r\n            \u0022team-join\u0022 =\u003E data.Deserialize\u003CTeamJoinEventData\u003E(options),\r\n            \u0022team-create\u0022 =\u003E data.Deserialize\u003CTeamCreateEventData\u003E(options),\r\n            \u0022forum-post\u0022 =\u003E data.Deserialize\u003CForumPostEventData\u003E(options),\r\n            \u0022ublog-post\u0022 =\u003E data.Deserialize\u003CUblogPostEventData\u003E(options),\r\n            \u0022tour-join\u0022 =\u003E data.Deserialize\u003CTourJoinEventData\u003E(options),\r\n            \u0022game-end\u0022 =\u003E data.Deserialize\u003CGameEndEventData\u003E(options),\r\n            \u0022simul-create\u0022 =\u003E data.Deserialize\u003CSimulCreateEventData\u003E(options),\r\n            \u0022simul-join\u0022 =\u003E data.Deserialize\u003CSimulJoinEventData\u003E(options),\r\n            \u0022study-like\u0022 =\u003E data.Deserialize\u003CStudyLikeEventData\u003E(options),\r\n            \u0022plan-start\u0022 =\u003E data.Deserialize\u003CPlanStartEventData\u003E(options),\r\n            \u0022plan-renew\u0022 =\u003E data.Deserialize\u003CPlanRenewEventData\u003E(options),\r\n            \u0022blog-post\u0022 =\u003E data.Deserialize\u003CBlogPostEventData\u003E(options),\r\n            \u0022ublog-post-like\u0022 =\u003E data.Deserialize\u003CUblogPostLikeEventData\u003E(options),\r\n            \u0022stream-start\u0022 =\u003E data.Deserialize\u003CStreamStartEventData\u003E(options),\r\n            _ =\u003E null\r\n        };\r\n\r\n        return result ?? new UnknownEventData();\r\n    }\r\n}\r\n\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Converters/PermissionJsonConverter.cs","FileName":"PermissionJsonConverter.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nusing System.Text.Json;\r\nusing System.Text.Json.Serialization;\r\nusing LichessNET.Entities.Enumerations;\r\n\r\nnamespace LichessNET.Converters;\r\n\r\npublic class PermissionJsonConverter : JsonConverter\u003CList\u003CTokenPermission\u003E\u003E\r\n{\r\n    public override List\u003CTokenPermission\u003E? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\r\n    {\r\n\r\n        var permissions = reader.GetString();\r\n        string[] permissionsList = permissions.Split(\u0027,\u0027);\r\n        List\u003CTokenPermission\u003E tokenPermissions = new List\u003CTokenPermission\u003E();\r\n\r\n        foreach (string permission in permissionsList)\r\n        {\r\n            switch (permission)\r\n            {\r\n                case \u0022email:read\u0022:\r\n                    tokenPermissions.Add(TokenPermission.ReadEmail);\r\n                    break;\r\n                case \u0022preference:read\u0022:\r\n                    tokenPermissions.Add(TokenPermission.ReadPreferences);\r\n                    break;\r\n                case \u0022preference:write\u0022:\r\n                    tokenPermissions.Add(TokenPermission.WritePreferences);\r\n                    break;\r\n                case \u0022follow:read\u0022:\r\n                    tokenPermissions.Add(TokenPermission.ReadFollows);\r\n                    break;\r\n                case \u0022follow:write\u0022:\r\n                    tokenPermissions.Add(TokenPermission.WriteFollows);\r\n                    break;\r\n                case \u0022msg:write\u0022:\r\n                    tokenPermissions.Add(TokenPermission.WriteMessages);\r\n                    break;\r\n                case \u0022challenge:read\u0022:\r\n                    tokenPermissions.Add(TokenPermission.ReadChallenges);\r\n                    break;\r\n                case \u0022challenge:write\u0022:\r\n                    tokenPermissions.Add(TokenPermission.WriteChallenges);\r\n                    break;\r\n                case \u0022challenge:bulk\u0022:\r\n                    tokenPermissions.Add(TokenPermission.BulkChallenges);\r\n                    break;\r\n                case \u0022tournament:write\u0022:\r\n                    tokenPermissions.Add(TokenPermission.WriteTournaments);\r\n                    break;\r\n                case \u0022team:read\u0022:\r\n                    tokenPermissions.Add(TokenPermission.ReadTeams);\r\n                    break;\r\n                case \u0022team:write\u0022:\r\n                    tokenPermissions.Add(TokenPermission.WriteTeams);\r\n                    break;\r\n                case \u0022team:lead\u0022:\r\n                    tokenPermissions.Add(TokenPermission.ManageTeams);\r\n                    break;\r\n                case \u0022puzzle:read\u0022:\r\n                    tokenPermissions.Add(TokenPermission.ReadPuzzleActivity);\r\n                    break;\r\n                case \u0022racer:write\u0022:\r\n                    tokenPermissions.Add(TokenPermission.WriteRaces);\r\n                    break;\r\n                case \u0022study:read\u0022:\r\n                    tokenPermissions.Add(TokenPermission.ReadStudies);\r\n                    break;\r\n                case \u0022study:write\u0022:\r\n                    tokenPermissions.Add(TokenPermission.WriteStudies);\r\n                    break;\r\n                case \u0022board:play\u0022:\r\n                    tokenPermissions.Add(TokenPermission.PlayGames);\r\n                    break;\r\n                case \u0022engine:read\u0022:\r\n                    tokenPermissions.Add(TokenPermission.ReadEngines);\r\n                    break;\r\n                case \u0022engine:write\u0022:\r\n                    tokenPermissions.Add(TokenPermission.ManageEngines);\r\n                    break;\r\n            }\r\n        }\r\n\r\n        return tokenPermissions;\r\n    }\r\n\r\n    public override void Write(Utf8JsonWriter writer, List\u003CTokenPermission\u003E value, JsonSerializerOptions options)\r\n    {\r\n        throw new NotImplementedException();\r\n    }\r\n}\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Entities/Game/GameStream.cs","FileName":"GameStream.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nusing LichessNET.API;\r\n\r\nnamespace LichessNET.Entities.Game;\r\n\r\n/// \u003Csummary\u003E\r\n/// Represents a stream for a Lichess game, handling real-time updates of moves and game information.\r\n/// \u003C/summary\u003E\r\npublic class GameStream\r\n{\r\n    public delegate void GameInfoFetchedHandler(object sender, OngoingGame game);\r\n    public delegate void MoveUpdateHandler(object sender, Move move);\r\n\r\n    private readonly Dictionary\u003Cstring, OngoingGame\u003E _games = new Dictionary\u003Cstring, OngoingGame\u003E();\r\n    private readonly LichessStream _stream;\r\n\r\n    public GameStream(string requestUri, string method = \u0022GET\u0022)\r\n        : this(requestUri, method, CancellationToken.None)\r\n    {\r\n    }\r\n\r\n    public GameStream(string requestUri, string method, CancellationToken cancellationToken)\r\n    {\r\n        _stream = new LichessStream(requestUri, method);\r\n        _stream.GameUpdateReceived \u002B= ProcessData;\r\n        _ = _stream.StreamGameAsync(cancellationToken);\r\n    }\r\n\r\n    public event MoveUpdateHandler? OnMoveMade;\r\n    public event GameInfoFetchedHandler? OnGameInfoFetched;\r\n\r\n    private void ProcessData(object sender, JsonElement data)\r\n    {\r\n        FetchDataForNewGame(data);\r\n        FetchDataForMove(data);\r\n    }\r\n\r\n    private void FetchDataForNewGame(JsonElement data)\r\n    {\r\n        if (!data.TryGetProperty(\u0022id\u0022, out var idProperty))\r\n            return;\r\n\r\n        var gameId = idProperty.GetString();\r\n        if (string.IsNullOrWhiteSpace(gameId))\r\n            return;\r\n\r\n        var game = new OngoingGame\r\n        {\r\n            GameId = gameId,\r\n            PlysAtInitFen = data.TryGetProperty(\u0022turns\u0022, out var turns) ? turns.GetInt32() : 0\r\n        };\r\n\r\n        _games[gameId] = game;\r\n        OnGameInfoFetched?.Invoke(this, game);\r\n    }\r\n\r\n    private void FetchDataForMove(JsonElement data)\r\n    {\r\n        if (!data.TryGetProperty(\u0022lm\u0022, out var lastMoveProperty))\r\n            return;\r\n\r\n        var gameId = _games.Count == 1 ? _games.First().Key : string.Empty;\r\n        if (string.IsNullOrWhiteSpace(gameId) || !_games.TryGetValue(gameId, out var game))\r\n            return;\r\n\r\n        game.Moves ??= new List\u003CMove\u003E();\r\n        var fen = data.TryGetProperty(\u0022fen\u0022, out var fenProperty) ? fenProperty.GetString() : string.Empty;\r\n        var move = new Move\r\n        {\r\n            Notation = lastMoveProperty.GetString(),\r\n            IsWhite = fen?.Contains(\u0022 w \u0022) ?? false,\r\n            GameID = gameId,\r\n            MoveNumber = (game.Moves.Count / 2) \u002B 1\r\n        };\r\n\r\n        game.Moves.Add(move);\r\n        OnMoveMade?.Invoke(this, move);\r\n    }\r\n}\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Entities/Game/TimeControl.cs","FileName":"TimeControl.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nnamespace LichessNET.Entities.Game;\r\n\r\npublic class TimeControl\r\n{\r\n    public string Type { get; set; }\r\n    public int Limit { get; set; }\r\n    public int Increment { get; set; }\r\n    public string Show { get; set; }\r\n}\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Entities/Puzzle/Dashboard/PuzzleResults.cs","FileName":"PuzzleResults.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nnamespace LichessNET.Entities.Puzzle.Dashboard;\r\n\r\npublic class PuzzleResults\r\n{\r\n    public int FirstWins { get; set; }\r\n    public int Nb { get; set; }\r\n    public int Performance { get; set; }\r\n    public int PuzzleRatingAvg { get; set; }\r\n    public int ReplayWins { get; set; }\r\n}\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Entities/Social/Stream/Streamer.cs","FileName":"Streamer.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nnamespace LichessNET.Entities.Social.Stream;\r\n\r\npublic class Streamer\r\n{\r\n    public string Name { get; set; }\r\n    public string Headline { get; set; }\r\n    public string Description { get; set; }\r\n    public string Twitch { get; set; }\r\n    public string YouTube { get; set; }\r\n    public string Image { get; set; }\r\n}\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Entities/Stats/Performance/Glicko.cs","FileName":"Glicko.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nnamespace LichessNET.Entities.Account.Performance;\r\n\r\npublic class Glicko\r\n{\r\n    public double Rating { get; set; }\r\n    public double Deviation { get; set; }\r\n    public bool Provisional { get; set; }\r\n}\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Entities/Stats/Performance/PerformanceStats.cs","FileName":"PerformanceStats.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nusing System.Text.Json.Serialization;\r\n\r\nnamespace LichessNET.Entities.Account.Performance;\r\n\r\npublic class PerformanceStats\r\n{\r\n    public string User { get; set; }\r\n    public Perf Perf { get; set; }\r\n    public int Rank { get; set; }\r\n    public double Percentile { get; set; }\r\n    public Stat Stat { get; set; }\r\n}\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Entities/Stats/Performance/StatEntities.cs","FileName":"StatEntities.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nnamespace LichessNET.Entities.Account.Performance;\r\n\r\npublic class PerfType\r\n{\r\n    public string Key { get; set; }\r\n    public string Name { get; set; }\r\n}\r\n\r\npublic class Highest\r\n{\r\n    public int Int { get; set; }\r\n    public DateTime At { get; set; }\r\n    public string GameId { get; set; }\r\n}\r\n\r\npublic class BestWins\r\n{\r\n    public List\u003CResult\u003E Results { get; set; }\r\n}\r\n\r\npublic class WorstLosses\r\n{\r\n    public List\u003CResult\u003E Results { get; set; }\r\n}\r\n\r\npublic class Result\r\n{\r\n    public int OpRating { get; set; }\r\n    public OpId OpId { get; set; }\r\n    public DateTime At { get; set; }\r\n    public string GameId { get; set; }\r\n}\r\n\r\npublic class OpId\r\n{\r\n    public string Id { get; set; }\r\n    public string Name { get; set; }\r\n}\r\n\r\npublic class Count\r\n{\r\n    public int All { get; set; }\r\n    public int Rated { get; set; }\r\n    public int Win { get; set; }\r\n    public int Loss { get; set; }\r\n    public int Draw { get; set; }\r\n    public int Tour { get; set; }\r\n    public int Berserk { get; set; }\r\n    public double OpAvg { get; set; }\r\n    public int Seconds { get; set; }\r\n    public int Disconnects { get; set; }\r\n}\r\n\r\npublic class ResultStreak\r\n{\r\n    public Streak Win { get; set; }\r\n    public Streak Loss { get; set; }\r\n}\r\n\r\npublic class Streak\r\n{\r\n    public Cur Cur { get; set; }\r\n    public Max Max { get; set; }\r\n}\r\n\r\npublic class Cur\r\n{\r\n    public int V { get; set; }\r\n}\r\n\r\npublic class Max\r\n{\r\n    public int V { get; set; }\r\n    public From From { get; set; }\r\n    public To To { get; set; }\r\n}\r\n\r\npublic class From\r\n{\r\n    public DateTime At { get; set; }\r\n    public string GameId { get; set; }\r\n}\r\n\r\npublic class To\r\n{\r\n    public DateTime At { get; set; }\r\n    public string GameId { get; set; }\r\n}\r\n\r\npublic class UserId\r\n{\r\n    public string Id { get; set; }\r\n    public string Name { get; set; }\r\n    public string Title { get; set; }\r\n}\r\n\r\npublic class PlayStreak\r\n{\r\n    public Nb Nb { get; set; }\r\n    public Time Time { get; set; }\r\n    public DateTime LastDate { get; set; }\r\n}\r\n\r\npublic class Nb\r\n{\r\n    public Cur Cur { get; set; }\r\n    public Max Max { get; set; }\r\n}\r\n\r\npublic class Time\r\n{\r\n    public Cur Cur { get; set; }\r\n    public Max Max { get; set; }\r\n}\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Entities/Teams/LichessTeam.cs","FileName":"LichessTeam.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nusing LichessNET.Entities.Social;\r\n\r\nnamespace LichessNET.Entities.Teams;\r\n\r\n/// \u003Csummary\u003E\r\n/// Represents a team on Lichess, containing information such as its ID, name, description, and members.\r\n/// \u003C/summary\u003E\r\npublic class LichessTeam\r\n{\r\n    public string Id { get; set; }\r\n    public string Name { get; set; }\r\n    public string Description { get; set; }\r\n    public string Flair { get; set; }\r\n    public TeamLeader Leader { get; set; }\r\n    public List\u003CTeamLeader\u003E Leaders { get; set; }\r\n    public int NbMembers { get; set; }\r\n    public bool Open { get; set; }\r\n    public bool Joined { get; set; }\r\n    public bool Requested { get; set; }\r\n}\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Entities/Teams/TeamLeader.cs","FileName":"TeamLeader.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nnamespace LichessNET.Entities.Social;\r\n\r\n/// \u003Csummary\u003E\r\n/// Represents a leader of a team on Lichess, providing properties for flair, identification, name, and patron status.\r\n/// \u003C/summary\u003E\r\npublic class TeamLeader\r\n{\r\n    public string Flair { get; set; }\r\n    public string Id { get; set; }\r\n    public string Name { get; set; }\r\n    public bool Patron { get; set; }\r\n}\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Internal/LichessLog.cs","FileName":"LichessLog.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nnamespace LichessNET.Internal;\r\n\r\ninternal sealed class LichessLog\r\n{\r\n\tprivate readonly string _name;\r\n\tprivate readonly bool _enabled;\r\n\r\n\tpublic LichessLog( string name, bool enabled = true )\r\n\t{\r\n\t\t_name = name;\r\n\t\t_enabled = enabled;\r\n\t}\r\n\r\n\tpublic void Debug( string message )\r\n\t{\r\n\t\tif ( _enabled )\r\n\t\t\tLog.Info( $\u0022[{_name}] {message}\u0022 );\r\n\t}\r\n\r\n\tpublic void Information( string message )\r\n\t{\r\n\t\tif ( _enabled )\r\n\t\t\tLog.Info( $\u0022[{_name}] {message}\u0022 );\r\n\t}\r\n\r\n\tpublic void Warning( string message )\r\n\t{\r\n\t\tif ( _enabled )\r\n\t\t\tLog.Warning( $\u0022[{_name}] {message}\u0022 );\r\n\t}\r\n\r\n\tpublic void Error( string message )\r\n\t{\r\n\t\tif ( _enabled )\r\n\t\t\tLog.Error( $\u0022[{_name}] {message}\u0022 );\r\n\t}\r\n}\r\n\r\n\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"API/LichessApiException.cs","FileName":"LichessApiException.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\n\nnamespace LichessNET.API;\n\n/// \u003Csummary\u003E\n/// A sanitized failure returned by the Lichess API.\n/// \u003C/summary\u003E\npublic sealed class LichessApiException : HttpRequestException\n{\n    public LichessApiException(HttpStatusCode? statusCode = null)\n        : this(CreateMessage(statusCode), statusCode)\n    {\n    }\n\n    private LichessApiException(string message, HttpStatusCode? statusCode)\n        : base(message, null, statusCode)\n    {\n    }\n\n    internal static LichessApiException InvalidResponse(HttpStatusCode statusCode)\n    {\n        return new LichessApiException(\n            \u0022Lichess API returned a response that could not be processed.\u0022, statusCode);\n    }\n\n    private static string CreateMessage(HttpStatusCode? statusCode)\n    {\n        return statusCode.HasValue\n            ? $\u0022Lichess API request failed with HTTP status {(int)statusCode.Value} ({statusCode.Value}).\u0022\n            : \u0022Lichess API request failed before an HTTP status was received.\u0022;\n    }\n}\n"},{"Ident":"brycpt.lichessnetport","Path":"API/OAuthAPI.cs","FileName":"OAuthAPI.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nusing LichessNET.Entities.OAuth;\r\n\r\nnamespace LichessNET.API;\r\n\r\npublic partial class LichessApiClient\r\n{\r\n    /// \u003Csummary\u003E\r\n    /// Tests OAuth tokens without placing them in the request URI or logs.\r\n    /// \u003C/summary\u003E\r\n    public Task\u003CDictionary\u003Cstring, TokenInfo?\u003E\u003E TestTokensAsync(List\u003Cstring\u003E tokens)\r\n    {\r\n        return TestTokensAsync(tokens, CancellationToken.None);\r\n    }\r\n\r\n    public async Task\u003CDictionary\u003Cstring, TokenInfo?\u003E\u003E TestTokensAsync(List\u003Cstring\u003E tokens,\r\n        CancellationToken cancellationToken = default)\r\n    {\r\n        if (tokens == null)\r\n            throw new ArgumentNullException(nameof(tokens));\r\n\r\n        if (tokens.Count == 0 || tokens.Count \u003E 1000)\r\n            throw new ArgumentOutOfRangeException(nameof(tokens),\r\n                \u0022Between 1 and 1000 OAuth tokens are required.\u0022);\r\n\r\n        if (tokens.Any(string.IsNullOrWhiteSpace))\r\n            throw new ArgumentException(\u0022OAuth tokens cannot be empty.\u0022, nameof(tokens));\r\n\r\n        cancellationToken.ThrowIfCancellationRequested();\r\n\r\n        var request = GetRequestScaffold(\u0022api/token/test\u0022);\r\n        var requestContent = new StringContent(\r\n            string.Join(\u0027,\u0027, tokens), Encoding.UTF8, \u0022text/plain\u0022);\r\n        var response = await SendRequest(request, \u0022POST\u0022, useToken: false,\r\n            cancellationToken: cancellationToken, requestContent: requestContent);\r\n\r\n        cancellationToken.ThrowIfCancellationRequested();\r\n        try\r\n        {\r\n            return await response.Content.ReadFromJsonAsync\u003CDictionary\u003Cstring, TokenInfo?\u003E\u003E(\r\n                       LichessJson.Options)\r\n                   ?? new Dictionary\u003Cstring, TokenInfo?\u003E();\r\n        }\r\n        catch (Exception exception) when (exception is not OperationCanceledException)\r\n        {\r\n            throw LichessApiException.InvalidResponse(response.StatusCode);\r\n        }\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    /// Deletes a token.\r\n    /// \u003C/summary\u003E\r\n    public async Task DeleteTokenAsync(string token)\r\n    {\r\n        var request = GetRequestScaffold(\u0022api/token\u0022);\r\n        request.Headers[\u0022Authorization\u0022] = \u0022Bearer \u0022 \u002B token;\r\n        await SendRequest(request, \u0022DELETE\u0022, useToken: false);\r\n    }\r\n}\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Code/API/TeamAPI.cs","FileName":"TeamAPI.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nusing LichessNET.Entities.Teams;\r\nusing LichessNET.Entities.Tournament;\r\nusing LichessNET.Entities.Tournament.Arena;\r\n\r\nnamespace LichessNET.API;\r\n\r\npublic partial class LichessApiClient\r\n{\r\n    /// \u003Csummary\u003E\r\n    ///     Get the team with the specified ID\r\n    /// \u003C/summary\u003E\r\n    /// \u003Cparam name=\u0022teamId\u0022\u003EThe ID of the team\u003C/param\u003E\r\n    /// \u003Creturns\u003EThe team with the specified ID\u003C/returns\u003E\r\n    public async Task\u003CLichessTeam\u003E GetTeamAsync(string teamId)\r\n    {\r\n        await _ratelimitController.Consume();\r\n        var request = GetRequestScaffold($\u0022api/team/{teamId}\u0022);\r\n        var response = await SendRequest(request);\r\n\r\n        var content = await response.Content.ReadAsStringAsync();\r\n        var team = LichessJson.Deserialize\u003CLichessTeam\u003E(content);\r\n\r\n        return team;\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    /// Gets the most populat teams on Lichess in a paginated manner.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Cparam name=\u0022page\u0022\u003EPage number, defaults to 1\u003C/param\u003E\r\n    /// \u003Creturns\u003EThe list of the most popular teams on the specified page.\u003C/returns\u003E\r\n    public async Task\u003CList\u003CLichessTeam\u003E\u003E GetPopularTeamsAsync(int page = 1)\r\n    {\r\n        await _ratelimitController.Consume();\r\n        var request = GetRequestScaffold(\u0022api/team/all\u0022, new Tuple\u003Cstring, string\u003E(\u0022page\u0022, page.ToString()));\r\n        var response = await SendRequest(request);\r\n\r\n        var content = await response.Content.ReadAsStringAsync();\r\n                var json = LichessJson.Parse(content);\r\n        return json.TryGetProperty(\u0022currentPageResults\u0022, out var results)\r\n            ? results.Deserialize\u003CList\u003CLichessTeam\u003E\u003E(LichessJson.Options) ?? new List\u003CLichessTeam\u003E()\r\n            : new List\u003CLichessTeam\u003E();\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    /// Get the list of teams that the specified user is in.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Cparam name=\u0022username\u0022\u003EThe username of the user\u003C/param\u003E\r\n    /// \u003Creturns\u003EA list of teams that the specified user is in\u003C/returns\u003E\r\n    public async Task\u003CList\u003CLichessTeam\u003E\u003E GetTeamOfUserAsync(string username)\r\n    {\r\n        await _ratelimitController.Consume();\r\n\r\n        var request = GetRequestScaffold($\u0022api/team/of/{username}\u0022);\r\n        var response = await SendRequest(request);\r\n\r\n        var content = await response.Content.ReadAsStringAsync();\r\n        var teams = LichessJson.Deserialize\u003CList\u003CLichessTeam\u003E\u003E(content);\r\n\r\n        return teams;\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    /// This funciton gets the members of a team, in chronoclogical order of joining the team. (Latest first),\r\n    /// with up to 5000 members.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Cparam name=\u0022teamId\u0022\u003EID of the Team\u003C/param\u003E\r\n    /// \u003Creturns\u003E\u003C/returns\u003E\r\n    public async Task\u003CList\u003CTeamMember\u003E\u003E GetTeamMembersAsync(string teamId)\r\n    {\r\n        await _ratelimitController.Consume();\r\n        var request = GetRequestScaffold($\u0022api/team/{teamId}/users\u0022);\r\n\r\n        var response = await SendRequest(request);\r\n\r\n        var content = await response.Content.ReadAsStringAsync();\r\n        var members = LichessJson.Deserialize\u003CList\u003CTeamMember\u003E\u003E(content);\r\n\r\n        return members;\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    /// Retrieves all Swiss tournaments of a team.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Cparam name=\u0022teamId\u0022\u003EThe ID of the team.\u003C/param\u003E\r\n    /// \u003Cparam name=\u0022max\u0022\u003EThe maximum number of tournaments to download. Default is 100.\u003C/param\u003E\r\n    /// \u003Creturns\u003EA task representing the asynchronous operation, containing the list of Swiss tournaments.\u003C/returns\u003E\r\n    public async Task\u003CList\u003CSwissTournament\u003E\u003E GetTeamSwissTournamentsAsync(string teamId, int max = 100)\r\n    {\r\n        await _ratelimitController.Consume();\r\n\r\n        var endpoint = $\u0022api/team/{teamId}/swiss?max={max}\u0022;\r\n        var request = GetRequestScaffold(endpoint);\r\n\r\n        var response = await SendRequest(request);\r\n        var content = await response.Content.ReadAsStringAsync();\r\n\r\n        var tournaments = new List\u003CSwissTournament\u003E();\r\n        foreach (var line in content.Split(\u0027\\n\u0027)) { if (string.IsNullOrWhiteSpace(line)) continue; var tournament = LichessJson.Deserialize\u003CSwissTournament\u003E(line.Trim()); if (tournament != null) tournaments.Add(tournament); }\r\n\r\n        return tournaments;\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    /// Retrieves all Arena tournaments relevant to a team.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Cparam name=\u0022teamId\u0022\u003EThe ID of the team.\u003C/param\u003E\r\n    /// \u003Cparam name=\u0022max\u0022\u003EThe maximum number of tournaments to download. Default is 100.\u003C/param\u003E\r\n    /// \u003Creturns\u003EA task representing the asynchronous operation, containing the list of Arena tournaments.\u003C/returns\u003E\r\n    public async Task\u003CList\u003CArenaTournament\u003E\u003E GetTeamArenaTournamentsAsync(string teamId, int max = 100)\r\n    {\r\n        await _ratelimitController.Consume();\r\n\r\n        var endpoint = $\u0022api/team/{teamId}/arena?max={max}\u0022;\r\n        var request = GetRequestScaffold(endpoint);\r\n\r\n        var response = await SendRequest(request);\r\n        var content = await response.Content.ReadAsStringAsync();\r\n\r\n        var tournaments = new List\u003CArenaTournament\u003E();\r\n        foreach (var line in content.Split(\u0027\\n\u0027)) { if (string.IsNullOrWhiteSpace(line)) continue; var tournament = LichessJson.Deserialize\u003CArenaTournament\u003E(line.Trim()); if (tournament != null) tournaments.Add(tournament); }\r\n\r\n        return tournaments;\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    /// Joins a team.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Cparam name=\u0022teamId\u0022\u003EThe ID of the team.\u003C/param\u003E\r\n    /// \u003Cparam name=\u0022message\u0022\u003EThe message for the team join request, required if the team manually reviews admission requests.\u003C/param\u003E\r\n    /// \u003Cparam name=\u0022password\u0022\u003EThe password for the team, if required.\u003C/param\u003E\r\n    /// \u003Creturns\u003EA task representing the asynchronous operation, containing the join team response.\u003C/returns\u003E\r\n    public async Task\u003Cbool\u003E JoinTeamAsync(string teamId, string message = null, string password = null)\r\n    {\r\n        await _ratelimitController.Consume();\r\n\r\n        var endpoint = $\u0022team/{teamId}/join\u0022;\r\n        var request = GetRequestScaffold(endpoint);\r\n\r\n        var formData = new Dictionary\u003Cstring, string\u003E();\r\n        if (!string.IsNullOrEmpty(message))\r\n        {\r\n            formData.Add(\u0022message\u0022, message);\r\n        }\r\n\r\n        if (!string.IsNullOrEmpty(password))\r\n        {\r\n            formData.Add(\u0022password\u0022, password);\r\n        }\r\n\r\n        var response = await SendRequest(request, \u0022POST\u0022, formData: formData);\r\n        var content = await response.Content.ReadAsStringAsync();\r\n\r\n        return content.Contains(\u0022true\u0022);\r\n    }\r\n\r\n    /// \u003Csummary\u003E\r\n    /// Leaves a team.\r\n    /// \u003C/summary\u003E\r\n    /// \u003Cparam name=\u0022teamId\u0022\u003EThe ID of the team.\u003C/param\u003E\r\n    /// \u003Creturns\u003EA task representing the asynchronous operation, containing the leave team response.\u003C/returns\u003E\r\n    public async Task\u003Cbool\u003E LeaveTeamAsync(string teamId)\r\n    {\r\n        await _ratelimitController.Consume();\r\n\r\n        var endpoint = $\u0022team/{teamId}/quit\u0022;\r\n        var request = GetRequestScaffold(endpoint);\r\n\r\n        var response = await SendRequest(request, \u0022POST\u0022);\r\n        var content = await response.Content.ReadAsStringAsync();\r\n\r\n        return content.Contains(\u0022true\u0022);\r\n    }\r\n}\r\n\r\n\r\n\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Code/Entities/Game/GamePlayer.cs","FileName":"GamePlayer.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nusing LichessNET.Entities.Enumerations;\r\n\r\nnamespace LichessNET.Entities.Game;\r\n\r\n/// \u003Csummary\u003E\r\n/// Represents a player in a chess game, including their name, title, and rating.\r\n/// This class will be used when parsing PGN Files\r\n/// \u003C/summary\u003E\r\npublic class GamePlayer\r\n{\r\n    public string Name { get; set; }\r\n\r\n    //TODO: Add serialization for Title\r\n    public Title? Title { get; set; }\r\n    public int Rating { get; set; }\r\n}\r\n\r\n"},{"Ident":"brycpt.lichessnetport","Path":"Entities/Board/BoardModels.cs","FileName":"BoardModels.cs","PackageType":"library","CodeKind":"Game","AssetVersionId":308901,"IsPrivate":false,"Code":"#nullable enable annotations\r\n\r\nusing System.Globalization;\r\nusing LichessNET.Entities.Enumerations;\r\nusing LichessNET.Extensions;\r\n\r\nnamespace LichessNET.Entities.Board;\r\n\r\npublic enum BoardColorPreference\r\n{\r\n    Random,\r\n    White,\r\n    Black\r\n}\r\n\r\npublic enum BoardChatRoom\r\n{\r\n    Player,\r\n    Spectator\r\n}\r\n\r\npublic sealed class BoardSeekOptions\r\n{\r\n    public bool Rated { get; set; }\r\n    public double TimeMinutes { get; set; } = 5;\r\n    public int IncrementSeconds { get; set; }\r\n    public int? DaysPerTurn { get; set; }\r\n    public BoardColorPreference Color { get; set; } = BoardColorPreference.Random;\r\n    public ChessVariant Variant { get; set; } = ChessVariant.Standard;\r\n    public string RatingRange { get; set; }\r\n\r\n    internal Dictionary\u003Cstring, string\u003E ToFormData()\r\n    {\r\n        Validate();\r\n\r\n        var form = new Dictionary\u003Cstring, string\u003E\r\n        {\r\n            [\u0022rated\u0022] = Rated.ToString().ToLowerInvariant(),\r\n            [\u0022variant\u0022] = Variant.ToApiName(),\r\n            [\u0022color\u0022] = ToApiName(Color)\r\n        };\r\n\r\n        if (DaysPerTurn.HasValue)\r\n        {\r\n            form[\u0022days\u0022] = DaysPerTurn.Value.ToString(CultureInfo.InvariantCulture);\r\n        }\r\n        else\r\n        {\r\n            form[\u0022time\u0022] = TimeMinutes.ToString(CultureInfo.InvariantCulture);\r\n            form[\u0022increment\u0022] = IncrementSeconds.ToString(CultureInfo.InvariantCulture);\r\n        }\r\n\r\n        if (!string.IsNullOrWhiteSpace(RatingRange))\r\n            form[\u0022ratingRange\u0022] = RatingRange;\r\n\r\n        return form;\r\n    }\r\n\r\n    private void Validate()\r\n    {\r\n        if (DaysPerTurn.HasValue)\r\n        {\r\n            if (DaysPerTurn.Value \u003C 1 || DaysPerTurn.Value \u003E 14)\r\n                throw new ArgumentOutOfRangeException(nameof(DaysPerTurn), \u0022Days per turn must be between 1 and 14.\u0022);\r\n\r\n            return;\r\n        }\r\n\r\n        if (TimeMinutes \u003C= 0 || TimeMinutes \u003E 180)\r\n            throw new ArgumentOutOfRangeException(nameof(TimeMinutes), \u0022Clock time must be between 0 and 180 minutes.\u0022);\r\n\r\n        if (IncrementSeconds \u003C 0 || IncrementSeconds \u003E 180)\r\n            throw new ArgumentOutOfRangeException(nameof(IncrementSeconds), \u0022Increment must be between 0 and 180 seconds.\u0022);\r\n    }\r\n\r\n    private static string ToApiName(BoardColorPreference color)\r\n    {\r\n        return color switch\r\n        {\r\n            BoardColorPreference.White =\u003E \u0022white\u0022,\r\n            BoardColorPreference.Black =\u003E \u0022black\u0022,\r\n            _ =\u003E \u0022random\u0022\r\n        };\r\n    }\r\n}\r\n\r\npublic sealed class BoardGameInfo\r\n{\r\n    [JsonPropertyName(\u0022gameId\u0022)]\r\n    public string GameId { get; set; }\r\n\r\n    [JsonPropertyName(\u0022id\u0022)]\r\n    public string Id { get; set; }\r\n\r\n    [JsonPropertyName(\u0022fullId\u0022)]\r\n    public string FullId { get; set; }\r\n\r\n    [JsonPropertyName(\u0022color\u0022)]\r\n    public string Color { get; set; }\r\n\r\n    [JsonPropertyName(\u0022fen\u0022)]\r\n    public string Fen { get; set; }\r\n\r\n    [JsonPropertyName(\u0022hasMoved\u0022)]\r\n    public bool? HasMoved { get; set; }\r\n\r\n    [JsonPropertyName(\u0022isMyTurn\u0022)]\r\n    public bool? IsMyTurn { get; set; }\r\n\r\n    [JsonPropertyName(\u0022lastMove\u0022)]\r\n    public string LastMove { get; set; }\r\n\r\n    [JsonPropertyName(\u0022source\u0022)]\r\n    public string Source { get; set; }\r\n\r\n    [JsonPropertyName(\u0022status\u0022)]\r\n    public string Status { get; set; }\r\n\r\n    [JsonPropertyName(\u0022variant\u0022)]\r\n    [JsonConverter(typeof(BoardObjectNameConverter))]\r\n    public string Variant { get; set; }\r\n\r\n    [JsonPropertyName(\u0022speed\u0022)]\r\n    public string Speed { get; set; }\r\n\r\n    [JsonPropertyName(\u0022perf\u0022)]\r\n    [JsonConverter(typeof(BoardObjectNameConverter))]\r\n    public string Perf { get; set; }\r\n\r\n    [JsonPropertyName(\u0022rated\u0022)]\r\n    public bool? Rated { get; set; }\r\n\r\n    [JsonPropertyName(\u0022opponent\u0022)]\r\n    public BoardPlayerInfo Opponent { get; set; }\r\n\r\n    [JsonPropertyName(\u0022white\u0022)]\r\n    public BoardPlayerInfo White { get; set; }\r\n\r\n    [JsonPropertyName(\u0022black\u0022)]\r\n    public BoardPlayerInfo Black { get; set; }\r\n\r\n    [JsonPropertyName(\u0022state\u0022)]\r\n    public BoardGameState State { get; set; }\r\n\r\n    [JsonExtensionData]\r\n    public Dictionary\u003Cstring, JsonElement\u003E Extra { get; set; }\r\n\r\n    public string BestGameId =\u003E !string.IsNullOrWhiteSpace(GameId) ? GameId : Id;\r\n}\r\n\r\npublic sealed class BoardPlayerInfo\r\n{\r\n    [JsonPropertyName(\u0022id\u0022)]\r\n    public string Id { get; set; }\r\n\r\n    [JsonPropertyName(\u0022name\u0022)]\r\n    public string Name { get; set; }\r\n\r\n    [JsonPropertyName(\u0022username\u0022)]\r\n    public string Username { get; set; }\r\n\r\n    [JsonPropertyName(\u0022title\u0022)]\r\n    public string Title { get; set; }\r\n\r\n    [JsonPropertyName(\u0022rating\u0022)]\r\n    public int? Rating { get; set; }\r\n\r\n    [JsonPropertyName(\u0022provisional\u0022)]\r\n    public bool? Provisional { get; set; }\r\n\r\n    [JsonExtensionData]\r\n    public Dictionary\u003Cstring, JsonElement\u003E Extra { get; set; }\r\n}\r\n\r\npublic sealed class BoardClockState\r\n{\r\n    public int? WhiteTimeMilliseconds { get; set; }\r\n    public int? BlackTimeMilliseconds { get; set; }\r\n    public int? WhiteIncrementMilliseconds { get; set; }\r\n    public int? BlackIncrementMilliseconds { get; set; }\r\n\r\n    public TimeSpan? WhiteTime =\u003E WhiteTimeMilliseconds.HasValue\r\n        ? TimeSpan.FromMilliseconds(WhiteTimeMilliseconds.Value)\r\n        : null;\r\n\r\n    public TimeSpan? BlackTime =\u003E BlackTimeMilliseconds.HasValue\r\n        ? TimeSpan.FromMilliseconds(BlackTimeMilliseconds.Value)\r\n        : null;\r\n\r\n    public static BoardClockState FromState(BoardGameState state)\r\n    {\r\n        return new BoardClockState\r\n        {\r\n            WhiteTimeMilliseconds = state?.WhiteTimeMilliseconds,\r\n            BlackTimeMilliseconds = state?.BlackTimeMilliseconds,\r\n            WhiteIncrementMilliseconds = state?.WhiteIncrementMilliseconds,\r\n            BlackIncrementMilliseconds = state?.BlackIncrementMilliseconds\r\n        };\r\n    }\r\n}\r\n\r\npublic sealed class BoardGameState\r\n{\r\n    [JsonPropertyName(\u0022type\u0022)]\r\n    public string Type { get; set; }\r\n\r\n    [JsonPropertyName(\u0022moves\u0022)]\r\n    public string Moves { get; set; }\r\n\r\n    [JsonPropertyName(\u0022wtime\u0022)]\r\n    public int? WhiteTimeMilliseconds { get; set; }\r\n\r\n    [JsonPropertyName(\u0022btime\u0022)]\r\n    public int? BlackTimeMilliseconds { get; set; }\r\n\r\n    [JsonPropertyName(\u0022winc\u0022)]\r\n    public int? WhiteIncrementMilliseconds { get; set; }\r\n\r\n    [JsonPropertyName(\u0022binc\u0022)]\r\n    public int? BlackIncrementMilliseconds { get; set; }\r\n\r\n    [JsonPropertyName(\u0022status\u0022)]\r\n    public string Status { get; set; }\r\n\r\n    [JsonPropertyName(\u0022winner\u0022)]\r\n    public string Winner { get; set; }\r\n\r\n    [JsonPropertyName(\u0022wdraw\u0022)]\r\n    public bool? WhiteOfferingDraw { get; set; }\r\n\r\n    [JsonPropertyName(\u0022bdraw\u0022)]\r\n    public bool? BlackOfferingDraw { get; set; }\r\n\r\n    [JsonExtensionData]\r\n    public Dictionary\u003Cstring, JsonElement\u003E Extra { get; set; }\r\n\r\n    public BoardClockState Clock =\u003E BoardClockState.FromState(this);\r\n\r\n    public bool IsFinished =\u003E !string.IsNullOrWhiteSpace(Status)\r\n                              \u0026\u0026 !Status.Equals(\u0022started\u0022, StringComparison.OrdinalIgnoreCase)\r\n                              \u0026\u0026 !Status.Equals(\u0022created\u0022, StringComparison.OrdinalIgnoreCase);\r\n\r\n    public IReadOnlyList\u003Cstring\u003E MoveList =\u003E BoardEventParser.SplitMoves(Moves);\r\n}\r\n\r\npublic sealed class BoardGameStartEvent\r\n{\r\n    [JsonPropertyName(\u0022type\u0022)]\r\n    public string Type { get; set; }\r\n\r\n    [JsonPropertyName(\u0022game\u0022)]\r\n    public BoardGameInfo Game { get; set; }\r\n}\r\n\r\npublic sealed class BoardGameFinishEvent\r\n{\r\n    [JsonPropertyName(\u0022type\u0022)]\r\n    public string Type { get; set; }\r\n\r\n    [JsonPropertyName(\u0022game\u0022)]\r\n    public BoardGameInfo Game { get; set; }\r\n}\r\n\r\npublic sealed class BoardGameFullEvent\r\n{\r\n    [JsonPropertyName(\u0022type\u0022)]\r\n    public string Type { get; set; }\r\n\r\n    [JsonPropertyName(\u0022id\u0022)]\r\n    public string Id { get; set; }\r\n\r\n    [JsonPropertyName(\u0022initialFen\u0022)]\r\n    public string InitialFen { get; set; }\r\n\r\n    [JsonPropertyName(\u0022rated\u0022)]\r\n    public bool? Rated { get; set; }\r\n\r\n    [JsonPropertyName(\u0022variant\u0022)]\r\n    [JsonConverter(typeof(BoardObjectNameConverter))]\r\n    public string Variant { get; set; }\r\n\r\n    [JsonPropertyName(\u0022speed\u0022)]\r\n    public string Speed { get; set; }\r\n\r\n    [JsonPropertyName(\u0022perf\u0022)]\r\n    [JsonConverter(typeof(BoardObjectNameConverter))]\r\n    public string Perf { get; set; }\r\n\r\n    [JsonPropertyName(\u0022createdAt\u0022)]\r\n    public long? CreatedAt { get; set; }\r\n\r\n    [JsonPropertyName(\u0022white\u0022)]\r\n    public BoardPlayerInfo White { get; set; }\r\n\r\n    [JsonPropertyName(\u0022black\u0022)]\r\n    public BoardPlayerInfo Black { get; set; }\r\n\r\n    [JsonPropertyName(\u0022state\u0022)]\r\n    public BoardGameState State { get; set; }\r\n\r\n    [JsonExtensionData]\r\n    public Dictionary\u003Cstring, JsonElement\u003E Extra { get; set; }\r\n}\r\n\r\npublic sealed class BoardChatLineEvent\r\n{\r\n    [JsonPropertyName(\u0022type\u0022)]\r\n    public string Type { get; set; }\r\n\r\n    [JsonPropertyName(\u0022room\u0022)]\r\n    public string Room { get; set; }\r\n\r\n    [JsonPropertyName(\u0022username\u0022)]\r\n    public string Username { get; set; }\r\n\r\n    [JsonPropertyName(\u0022text\u0022)]\r\n    public string Text { get; set; }\r\n}\r\n\r\npublic static class BoardEventParser\r\n{\r\n    public static string GetEventType(JsonElement element)\r\n    {\r\n        return element.TryGetProperty(\u0022type\u0022, out var type)\r\n            ? type.GetString()\r\n            : string.Empty;\r\n    }\r\n\r\n    public static BoardGameStartEvent ParseGameStart(JsonElement element)\r\n    {\r\n        return element.Deserialize\u003CBoardGameStartEvent\u003E(LichessJson.Options);\r\n    }\r\n\r\n    public static BoardGameFinishEvent ParseGameFinish(JsonElement element)\r\n    {\r\n        return element.Deserialize\u003CBoardGameFinishEvent\u003E(LichessJson.Options);\r\n    }\r\n\r\n    public static BoardGameFullEvent ParseGameFull(JsonElement element)\r\n    {\r\n        return element.Deserialize\u003CBoardGameFullEvent\u003E(LichessJson.Options);\r\n    }\r\n\r\n    public static BoardGameState ParseGameState(JsonElement element)\r\n    {\r\n        return element.Deserialize\u003CBoardGameState\u003E(LichessJson.Options);\r\n    }\r\n\r\n    public static BoardChatLineEvent ParseChatLine(JsonElement element)\r\n    {\r\n        return element.Deserialize\u003CBoardChatLineEvent\u003E(LichessJson.Options);\r\n    }\r\n\r\n    public static IReadOnlyList\u003Cstring\u003E SplitMoves(string moves)\r\n    {\r\n        if (string.IsNullOrWhiteSpace(moves))\r\n            return Array.Empty\u003Cstring\u003E();\r\n\r\n        return moves.Split(\u0027 \u0027, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);\r\n    }\r\n}\r\n\n\n/// \u003Csummary\u003E\n/// Preserves legacy string properties while accepting the object form used by\n/// current Board API gameFull payloads.\n/// \u003C/summary\u003E\npublic sealed class BoardObjectNameConverter : JsonConverter\u003Cstring\u003E\n{\n    public override string? Read(ref Utf8JsonReader reader, Type typeToConvert,\n        JsonSerializerOptions options)\n    {\n        if (reader.TokenType == JsonTokenType.String)\n            return reader.GetString();\n\n        if (reader.TokenType == JsonTokenType.Null)\n            return null;\n\n        using var document = JsonDocument.ParseValue(ref reader);\n        var value = document.RootElement;\n        if (value.ValueKind != JsonValueKind.Object)\n            return value.ToString();\n\n        foreach (var propertyName in new[] { \u0022key\u0022, \u0022name\u0022, \u0022short\u0022 })\n        {\n            if (value.TryGetProperty(propertyName, out var property) \u0026\u0026\n                property.ValueKind == JsonValueKind.String)\n            {\n                return property.GetString();\n            }\n        }\n\n        return value.GetRawText();\n    }\n\n    public override void Write(Utf8JsonWriter writer, string value,\n        JsonSerializerOptions options)\n    {\n        writer.WriteStringValue(value);\n    }\n}\n"}]}