diff --git a/.azure/pipelines/build-deploy.yml b/.azure/pipelines/build-deploy.yml new file mode 100644 index 0000000..9a3f973 --- /dev/null +++ b/.azure/pipelines/build-deploy.yml @@ -0,0 +1,26 @@ +trigger: + branches: + include: + - develop + - master + paths: + include: + - /src/* + +resources: + repositories: + - repository: devops + type: git + name: pub/devops + ref: master + + +jobs: +- template: dotnet-build-deploy.yml@devops + parameters: + versionPrefix: '0.1' + projectName: 'Web1.Sse.ChatApi' + hasUnitTests: false + createZip: true + createNugetPackage: false + createGithubRelease: true \ No newline at end of file diff --git a/src/Web1.Sse.Chat.sln b/src/Web1.Sse.Chat.sln new file mode 100644 index 0000000..f105ae0 --- /dev/null +++ b/src/Web1.Sse.Chat.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34701.34 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web1.Sse.ChatApi", "Web1.Sse.ChatApi\Web1.Sse.ChatApi.csproj", "{A0064768-9AD1-46AC-9005-2F5B1501B784}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A0064768-9AD1-46AC-9005-2F5B1501B784}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A0064768-9AD1-46AC-9005-2F5B1501B784}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A0064768-9AD1-46AC-9005-2F5B1501B784}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A0064768-9AD1-46AC-9005-2F5B1501B784}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9F52A468-AA55-44F7-B83A-320F7DFE70E4} + EndGlobalSection +EndGlobal diff --git a/src/Web1.Sse.ChatApi/Assets/IApiEndPoint.cs b/src/Web1.Sse.ChatApi/Assets/IApiEndPoint.cs new file mode 100644 index 0000000..042f5a1 --- /dev/null +++ b/src/Web1.Sse.ChatApi/Assets/IApiEndPoint.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Builder; + +namespace Web1.Sse.ChatApi.Assets +{ + public interface IApiEndPoint + { + void Map(WebApplication app); + } +} diff --git a/src/Web1.Sse.ChatApi/EndPoints/EndPointExtensions.cs b/src/Web1.Sse.ChatApi/EndPoints/EndPointExtensions.cs new file mode 100644 index 0000000..5264abe --- /dev/null +++ b/src/Web1.Sse.ChatApi/EndPoints/EndPointExtensions.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using System.Linq; +using System.Reflection; +using Web1.Sse.ChatApi.Assets; + +namespace Web1.Sse.ChatApi.EndPoints +{ + public static class EndPointExtensions + { + public static void UseApiEndPoints(this WebApplication app) + { + var endpointTypes = Assembly.GetExecutingAssembly().ExportedTypes.Where(x => x.GetInterface(nameof(IApiEndPoint)) is not null); + foreach (var endpointType in endpointTypes) + { + IApiEndPoint endPoint = (IApiEndPoint)ActivatorUtilities.CreateInstance(app.Services, endpointType); + endPoint.Map(app); + } + } + } +} diff --git a/src/Web1.Sse.ChatApi/EndPoints/MessagesEndPoint.cs b/src/Web1.Sse.ChatApi/EndPoints/MessagesEndPoint.cs new file mode 100644 index 0000000..4cd10c8 --- /dev/null +++ b/src/Web1.Sse.ChatApi/EndPoints/MessagesEndPoint.cs @@ -0,0 +1,39 @@ +using Code2.Web.SseTyped; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Linq; +using System.Security.Claims; +using Web1.Sse.ChatApi.Assets; +using Web1.Sse.ChatApi.Models; +using Web1.Sse.ChatApi.Services; + +namespace Web1.Sse.ChatApi.EndPoints +{ + public class MessagesEndPoint : IApiEndPoint + { + public MessagesEndPoint(ISecurityService securityService, ISseService sseService) + { + _securityService = securityService; + _sseService = sseService; + } + + private readonly ISseService _sseService; + private readonly ISecurityService _securityService; + + public void Map(WebApplication app) + { + app.MapPost("/messages", AddMessage); + } + + public IResult AddMessage([FromBody] ChatMessage message, ClaimsPrincipal principal) + { + message.FromUserId = _securityService.GetCurrentUserId(principal); + message.Created = DateTime.Now; + string[] userIds = message.ToUserIds.Select(x => x.ToString()).ToArray(); + _sseService.Send(message, (properties) => userIds.Length == 0 || userIds.Contains(properties["userId"])); + return Results.NoContent(); + } + } +} diff --git a/src/Web1.Sse.ChatApi/EndPoints/UsersEndPoint.cs b/src/Web1.Sse.ChatApi/EndPoints/UsersEndPoint.cs new file mode 100644 index 0000000..509a26d --- /dev/null +++ b/src/Web1.Sse.ChatApi/EndPoints/UsersEndPoint.cs @@ -0,0 +1,91 @@ +using Code2.Web.SseTyped; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; +using System; +using System.Security.Claims; +using Web1.Sse.ChatApi.Assets; +using Web1.Sse.ChatApi.Models; +using Web1.Sse.ChatApi.Services; + +namespace Web1.Sse.ChatApi.EndPoints +{ + public class UsersEndPoint : IApiEndPoint + { + + public UsersEndPoint(IUserRepository userRepository, ISseService sseService, ISecurityService securityService) + { + _userRepository = userRepository; + _sseService = sseService; + _securityService = securityService; + } + + private readonly IUserRepository _userRepository; + private readonly ISseService _sseService; + private readonly ISecurityService _securityService; + + public void Map(WebApplication app) + { + app.MapPost("/users/login", Login).AllowAnonymous(); + app.MapGet("/users", GetUsers); + app.MapPut("/users/{userId}", UpdateUser); + app.MapDelete("/users/{userId}", DeleteUser); + } + + public IResult Login(LoginRequest loginRequest) + { + try + { + ChatUser user = new ChatUser { Name = loginRequest.Name }; + int userId = _userRepository.Add(user); + _sseService.Send(new SystemMessage(SystemMessage.UserAddedMessageType, user)); + return Results.Ok(new LoginResponse { UserId = userId, Token = _securityService.GetToken(userId) }); + } + catch (Exception ex) + { + return Results.Problem(ex.Message); + } + } + + public IResult GetUsers() + { + return Results.Ok(_userRepository.Get()); + } + + public IResult UpdateUser(int userId, [FromBody] ChatUser user, ClaimsPrincipal principal) + { + if (!IsCurrentUserId(userId, principal)) return Results.Problem("Invalid operation"); + try + { + _userRepository.Update(userId, user); + _sseService.Send(new SystemMessage(SystemMessage.UserModifiedMessageType, user)); + return Results.NoContent(); + } + catch (Exception ex) + { + return Results.Problem(ex.Message); + } + } + + public IResult DeleteUser(int userId, ClaimsPrincipal principal) + { + if (!IsCurrentUserId(userId, principal)) return Results.Problem("Invalid operation"); + try + { + _userRepository.Delete(userId); + _sseService.Send(new SystemMessage(SystemMessage.UserRemovedMessageType, new ChatUser { Id = userId })); + return Results.NoContent(); + } + catch (Exception ex) + { + return Results.Problem(ex.Message); + } + } + + private bool IsCurrentUserId(int userId, ClaimsPrincipal principal) + => _securityService.GetCurrentUserId(principal) == userId; + + + } +} diff --git a/src/Web1.Sse.ChatApi/Models/ChatMessage.cs b/src/Web1.Sse.ChatApi/Models/ChatMessage.cs new file mode 100644 index 0000000..fb8af61 --- /dev/null +++ b/src/Web1.Sse.ChatApi/Models/ChatMessage.cs @@ -0,0 +1,13 @@ +using System; + +namespace Web1.Sse.ChatApi.Models +{ + public class ChatMessage + { + public int Id { get; set; } + public DateTime? Created { get; set; } + public int FromUserId { get; set; } + public int[] ToUserIds { get; set; } = Array.Empty(); + public string Text { get; set; } = string.Empty; + } +} diff --git a/src/Web1.Sse.ChatApi/Models/ChatUser.cs b/src/Web1.Sse.ChatApi/Models/ChatUser.cs new file mode 100644 index 0000000..c05793b --- /dev/null +++ b/src/Web1.Sse.ChatApi/Models/ChatUser.cs @@ -0,0 +1,8 @@ +namespace Web1.Sse.ChatApi.Models +{ + public class ChatUser + { + public int Id { get; set; } + public string Name { get; set; } = string.Empty; + } +} diff --git a/src/Web1.Sse.ChatApi/Models/LoginRequest.cs b/src/Web1.Sse.ChatApi/Models/LoginRequest.cs new file mode 100644 index 0000000..a678d38 --- /dev/null +++ b/src/Web1.Sse.ChatApi/Models/LoginRequest.cs @@ -0,0 +1,7 @@ +namespace Web1.Sse.ChatApi.Models +{ + public class LoginRequest + { + public string Name { get; set; } = string.Empty; + } +} diff --git a/src/Web1.Sse.ChatApi/Models/LoginResponse.cs b/src/Web1.Sse.ChatApi/Models/LoginResponse.cs new file mode 100644 index 0000000..426385c --- /dev/null +++ b/src/Web1.Sse.ChatApi/Models/LoginResponse.cs @@ -0,0 +1,8 @@ +namespace Web1.Sse.ChatApi.Models +{ + public class LoginResponse + { + public int UserId { get; set; } + public string Token { get; set; } = string.Empty; + } +} diff --git a/src/Web1.Sse.ChatApi/Models/SystemMessage.cs b/src/Web1.Sse.ChatApi/Models/SystemMessage.cs new file mode 100644 index 0000000..251517b --- /dev/null +++ b/src/Web1.Sse.ChatApi/Models/SystemMessage.cs @@ -0,0 +1,19 @@ +namespace Web1.Sse.ChatApi.Models +{ + public class SystemMessage + { + public SystemMessage(string messageType, object data) + { + MessageType = messageType; + Data = data; + } + + public const string UserModifiedMessageType = "UserModified"; + public const string UserAddedMessageType = "UserAdded"; + public const string UserRemovedMessageType = "UserRemoved"; + + public string MessageType { get; set; } + public object Data { get; private set; } + + } +} diff --git a/src/Web1.Sse.ChatApi/Program.cs b/src/Web1.Sse.ChatApi/Program.cs new file mode 100644 index 0000000..e593cde --- /dev/null +++ b/src/Web1.Sse.ChatApi/Program.cs @@ -0,0 +1,31 @@ +using Code2.Web.SseTyped; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Web1.Sse.ChatApi.EndPoints; +using Web1.Sse.ChatApi.Services; + +var builder = WebApplication.CreateBuilder(args); +// Add services to the container. +ISecurityService securityService = new SecurityService(builder.Configuration); +builder.Services.AddSingleton(); +builder.Services.AddSingleton(securityService); +builder.Services.AddSseTyped(); +builder.Services.AddCors(); +builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(securityService.ConfigureJwtBearer); +builder.Services.AddAuthorization(securityService.ConfigureAuthorization); + + +var app = builder.Build(); +// Configure the HTTP request pipeline. + +app.UseCors(x => x.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()); +app.UseStaticFiles(); +app.UseAuthentication(); +app.UseAuthorization(); + +app.UseApiEndPoints(); +app.UseSseTyped(rootPath: "/sse"); + + +app.Run(); diff --git a/src/Web1.Sse.ChatApi/Properties/launchSettings.json b/src/Web1.Sse.ChatApi/Properties/launchSettings.json new file mode 100644 index 0000000..55100ed --- /dev/null +++ b/src/Web1.Sse.ChatApi/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:13675", + "sslPort": 44315 + } + }, + "profiles": { + "Web1.Sse.ChatApi": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "index.html", + "applicationUrl": "http://localhost:5180", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "index.html", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/Web1.Sse.ChatApi/Services/ISecurityService.cs b/src/Web1.Sse.ChatApi/Services/ISecurityService.cs new file mode 100644 index 0000000..2a19d9c --- /dev/null +++ b/src/Web1.Sse.ChatApi/Services/ISecurityService.cs @@ -0,0 +1,14 @@ +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; +using System.Security.Claims; + +namespace Web1.Sse.ChatApi.Services +{ + public interface ISecurityService + { + void ConfigureJwtBearer(JwtBearerOptions options); + void ConfigureAuthorization(AuthorizationOptions options); + string GetToken(int userId); + int GetCurrentUserId(ClaimsPrincipal? principal); + } +} \ No newline at end of file diff --git a/src/Web1.Sse.ChatApi/Services/IUserRepository.cs b/src/Web1.Sse.ChatApi/Services/IUserRepository.cs new file mode 100644 index 0000000..376923b --- /dev/null +++ b/src/Web1.Sse.ChatApi/Services/IUserRepository.cs @@ -0,0 +1,14 @@ +using System; +using Web1.Sse.ChatApi.Models; + +namespace Web1.Sse.ChatApi.Services +{ + public interface IUserRepository + { + int Add(ChatUser user); + void Delete(int userId); + ChatUser[] Get(); + ChatUser[] Get(Func filter); + void Update(int userId, ChatUser user); + } +} \ No newline at end of file diff --git a/src/Web1.Sse.ChatApi/Services/SecurityService.cs b/src/Web1.Sse.ChatApi/Services/SecurityService.cs new file mode 100644 index 0000000..077ee85 --- /dev/null +++ b/src/Web1.Sse.ChatApi/Services/SecurityService.cs @@ -0,0 +1,66 @@ +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Configuration; +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Security.Claims; +using System.Text; + +namespace Web1.Sse.ChatApi.Services +{ + public class SecurityService : ISecurityService + { + public SecurityService(IConfiguration config) + { + _jwtAudience = config["Jwt:Audience"]; + _jwtIssuer = config["Jwt:Issuer"]; + _jwtSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["Jwt:Key"])); + } + + private string _jwtAudience; + private string _jwtIssuer; + private SymmetricSecurityKey _jwtSigningKey; + private string _userIdKey = "userId"; + + public void ConfigureJwtBearer(JwtBearerOptions options) + { + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = true, + ValidateAudience = true, + ValidateLifetime = true, + ValidateIssuerSigningKey = true, + ValidIssuer = _jwtIssuer, + ValidAudience = _jwtAudience, + IssuerSigningKey = _jwtSigningKey + }; + } + + public void ConfigureAuthorization(AuthorizationOptions options) + { + var builder = new AuthorizationPolicyBuilder(); + options.FallbackPolicy = builder.RequireAuthenticatedUser().Build(); + } + + public string GetToken(int userId) + { + DateTime expires = DateTime.Now.AddHours(12); + IEnumerable claims = new[] { new Claim(_userIdKey, userId.ToString()) }; + SigningCredentials credentials = new SigningCredentials(_jwtSigningKey, SecurityAlgorithms.HmacSha256); + JwtSecurityToken token = new JwtSecurityToken(issuer: _jwtIssuer, audience: _jwtAudience, signingCredentials: credentials, expires: expires, claims: claims); + JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler(); + return handler.WriteToken(token); + } + + public int GetCurrentUserId(ClaimsPrincipal? principal) + { + var id = (ClaimsIdentity?)principal?.Identity; + string? userIdString = id?.Claims.FirstOrDefault(x => x.Type == _userIdKey)?.Value; + if (userIdString is null) return 0; + return int.TryParse(userIdString, out int userId) ? userId : 0; + } + } +} diff --git a/src/Web1.Sse.ChatApi/Services/UserRepository.cs b/src/Web1.Sse.ChatApi/Services/UserRepository.cs new file mode 100644 index 0000000..cb51263 --- /dev/null +++ b/src/Web1.Sse.ChatApi/Services/UserRepository.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Web1.Sse.ChatApi.Models; + +namespace Web1.Sse.ChatApi.Services +{ + public class UserRepository : IUserRepository + { + public UserRepository() + { + _userProperties = typeof(ChatUser).GetProperties().Where(x => x.CanWrite).ToArray(); + } + + private readonly List _users = new List(); + private readonly object _lock = new object(); + private readonly PropertyInfo[] _userProperties; + private int _userIdSource; + + public int Add(ChatUser user) + { + ThrowOnExistingUserName(user.Name); + lock (_lock) + { + user.Id = ++_userIdSource; + _users.Add(user); + return _userIdSource; + } + } + + public void Update(int userId, ChatUser user) + { + ChatUser existing = GetOrThrowOnNonExistingUser(userId); + if (existing.Name != user.Name) ThrowOnExistingUserName(user.Name); + CopyProperties(user, existing, new[] { nameof(ChatUser.Id) }); + } + + public void Delete(int userId) + { + ChatUser existing = GetOrThrowOnNonExistingUser(userId); + lock (_lock) + { + _users.Remove(existing); + } + } + + public ChatUser[] Get() + => _users.ToArray(); + + public ChatUser[] Get(Func filter) + => _users.Where(filter).ToArray(); + + private ChatUser GetOrThrowOnNonExistingUser(int userId) + => _users.FirstOrDefault(x => x.Id == userId) ?? throw new InvalidOperationException("User does not exist"); + + private void ThrowOnExistingUserName(string userName) + { + if (_users.Any(x => x.Name == userName)) throw new InvalidOperationException($"User name {userName} already exists"); + } + + private void CopyProperties(ChatUser source, ChatUser target, string[] excludedPropertyNames) + { + foreach (var property in _userProperties) + { + if (excludedPropertyNames.Contains(property.Name)) continue; + object? value = property.GetValue(source, null); + property.SetValue(target, value, null); + } + } + } +} diff --git a/src/Web1.Sse.ChatApi/Web1.Sse.ChatApi.csproj b/src/Web1.Sse.ChatApi/Web1.Sse.ChatApi.csproj new file mode 100644 index 0000000..3de6768 --- /dev/null +++ b/src/Web1.Sse.ChatApi/Web1.Sse.ChatApi.csproj @@ -0,0 +1,30 @@ + + + + net6.0 + enable + disable + 11.0 + + + + + + + + + + Always + + + Always + + + Always + + + Always + + + + diff --git a/src/Web1.Sse.ChatApi/appsettings.Development.json b/src/Web1.Sse.ChatApi/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/src/Web1.Sse.ChatApi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/Web1.Sse.ChatApi/appsettings.json b/src/Web1.Sse.ChatApi/appsettings.json new file mode 100644 index 0000000..522236a --- /dev/null +++ b/src/Web1.Sse.ChatApi/appsettings.json @@ -0,0 +1,14 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "Jwt": { + "Issuer": "chatapi", + "Audience": "chatapi", + "Key": "wd%yhldc3s8Bktx0sw$fC0rFkaEd2d9n" + } +} diff --git a/src/Web1.Sse.ChatApi/wwwroot/index.html b/src/Web1.Sse.ChatApi/wwwroot/index.html new file mode 100644 index 0000000..58ed4a8 --- /dev/null +++ b/src/Web1.Sse.ChatApi/wwwroot/index.html @@ -0,0 +1,16 @@ + + + + + + + SSE Chat + + + + + +
+ + + \ No newline at end of file diff --git a/src/Web1.Sse.ChatApi/wwwroot/style.css b/src/Web1.Sse.ChatApi/wwwroot/style.css new file mode 100644 index 0000000..ad50334 --- /dev/null +++ b/src/Web1.Sse.ChatApi/wwwroot/style.css @@ -0,0 +1,9 @@ +/*! +Pure v3.0.0 +Copyright 2013 Yahoo! +Licensed under the BSD License. +https://github.com/pure-css/pure/blob/master/LICENSE +*//*! +normalize.css v | MIT License | https://necolas.github.io/normalize.css/ +Copyright (c) Nicolas Gallagher and Jonathan Neal +*//*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}html{font-family:sans-serif}.hidden,[hidden]{display:none!important}.pure-img{max-width:100%;height:auto;display:block}.pure-g{display:flex;flex-flow:row wrap;align-content:flex-start}.pure-u{display:inline-block;vertical-align:top}.pure-u-1,.pure-u-1-1,.pure-u-1-12,.pure-u-1-2,.pure-u-1-24,.pure-u-1-3,.pure-u-1-4,.pure-u-1-5,.pure-u-1-6,.pure-u-1-8,.pure-u-10-24,.pure-u-11-12,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-2-24,.pure-u-2-3,.pure-u-2-5,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24,.pure-u-3-24,.pure-u-3-4,.pure-u-3-5,.pure-u-3-8,.pure-u-4-24,.pure-u-4-5,.pure-u-5-12,.pure-u-5-24,.pure-u-5-5,.pure-u-5-6,.pure-u-5-8,.pure-u-6-24,.pure-u-7-12,.pure-u-7-24,.pure-u-7-8,.pure-u-8-24,.pure-u-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1-24{width:4.1667%}.pure-u-1-12,.pure-u-2-24{width:8.3333%}.pure-u-1-8,.pure-u-3-24{width:12.5%}.pure-u-1-6,.pure-u-4-24{width:16.6667%}.pure-u-1-5{width:20%}.pure-u-5-24{width:20.8333%}.pure-u-1-4,.pure-u-6-24{width:25%}.pure-u-7-24{width:29.1667%}.pure-u-1-3,.pure-u-8-24{width:33.3333%}.pure-u-3-8,.pure-u-9-24{width:37.5%}.pure-u-2-5{width:40%}.pure-u-10-24,.pure-u-5-12{width:41.6667%}.pure-u-11-24{width:45.8333%}.pure-u-1-2,.pure-u-12-24{width:50%}.pure-u-13-24{width:54.1667%}.pure-u-14-24,.pure-u-7-12{width:58.3333%}.pure-u-3-5{width:60%}.pure-u-15-24,.pure-u-5-8{width:62.5%}.pure-u-16-24,.pure-u-2-3{width:66.6667%}.pure-u-17-24{width:70.8333%}.pure-u-18-24,.pure-u-3-4{width:75%}.pure-u-19-24{width:79.1667%}.pure-u-4-5{width:80%}.pure-u-20-24,.pure-u-5-6{width:83.3333%}.pure-u-21-24,.pure-u-7-8{width:87.5%}.pure-u-11-12,.pure-u-22-24{width:91.6667%}.pure-u-23-24{width:95.8333%}.pure-u-1,.pure-u-1-1,.pure-u-24-24,.pure-u-5-5{width:100%}.pure-button{display:inline-block;line-height:normal;white-space:nowrap;vertical-align:middle;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;user-select:none;box-sizing:border-box}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-group{letter-spacing:-.31em;text-rendering:optimizespeed}.opera-only :-o-prefocus,.pure-button-group{word-spacing:-.43em}.pure-button-group .pure-button{letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-button{font-family:inherit;font-size:100%;padding:.5em 1em;color:#000c;border:none transparent;background-color:#e6e6e6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:focus,.pure-button:hover{background-image:linear-gradient(transparent,#0000000d 40%,#0000001a)}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px #00000026 inset,0 0 6px #0003 inset;border-color:#000}.pure-button-disabled,.pure-button-disabled:active,.pure-button-disabled:focus,.pure-button-disabled:hover,.pure-button[disabled]{border:none;background-image:none;opacity:.4;cursor:not-allowed;box-shadow:none;pointer-events:none}.pure-button-hidden{display:none}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-button-group .pure-button{margin:0;border-radius:0;border-right:1px solid rgba(0,0,0,.2)}.pure-button-group .pure-button:first-child{border-top-left-radius:2px;border-bottom-left-radius:2px}.pure-button-group .pure-button:last-child{border-top-right-radius:2px;border-bottom-right-radius:2px;border-right:none}.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;vertical-align:middle;box-sizing:border-box}.pure-form input:not([type]){padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;box-sizing:border-box}.pure-form input[type=color]{padding:.2em .5em}.pure-form input[type=color]:focus,.pure-form input[type=date]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=email]:focus,.pure-form input[type=month]:focus,.pure-form input[type=number]:focus,.pure-form input[type=password]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=text]:focus,.pure-form input[type=time]:focus,.pure-form input[type=url]:focus,.pure-form input[type=week]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;border-color:#129fea}.pure-form input:not([type]):focus{outline:0;border-color:#129fea}.pure-form input[type=checkbox]:focus,.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus{outline:thin solid #129FEA;outline:1px auto #129FEA}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=color][disabled],.pure-form input[type=date][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=email][disabled],.pure-form input[type=month][disabled],.pure-form input[type=number][disabled],.pure-form input[type=password][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=text][disabled],.pure-form input[type=time][disabled],.pure-form input[type=url][disabled],.pure-form input[type=week][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input:not([type])[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background-color:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form select:focus:invalid,.pure-form textarea:focus:invalid{color:#b94a48;border-color:#e9322d}.pure-form input[type=checkbox]:focus:invalid:focus,.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{height:2.25em;border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=color],.pure-form-stacked input[type=date],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=email],.pure-form-stacked input[type=file],.pure-form-stacked input[type=month],.pure-form-stacked input[type=number],.pure-form-stacked input[type=password],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=text],.pure-form-stacked input[type=time],.pure-form-stacked input[type=url],.pure-form-stacked input[type=week],.pure-form-stacked label,.pure-form-stacked select,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-stacked input:not([type]){display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned select,.pure-form-aligned textarea,.pure-form-message-inline{display:inline-block;vertical-align:middle}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 11em}.pure-form .pure-input-rounded,.pure-form input.pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input,.pure-form .pure-group textarea{display:block;padding:10px;margin:0 0 -1px;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus,.pure-form .pure-group textarea:focus{z-index:3}.pure-form .pure-group input:first-child,.pure-form .pure-group textarea:first-child{top:1px;border-radius:4px 4px 0 0;margin:0}.pure-form .pure-group input:first-child:last-child,.pure-form .pure-group textarea:first-child:last-child{top:1px;border-radius:4px;margin:0}.pure-form .pure-group input:last-child,.pure-form .pure-group textarea:last-child{top:-2px;border-radius:0 0 4px 4px;margin:0}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-3-4{width:75%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=color],.pure-group input[type=date],.pure-group input[type=datetime-local],.pure-group input[type=datetime],.pure-group input[type=email],.pure-group input[type=month],.pure-group input[type=number],.pure-group input[type=password],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=text],.pure-group input[type=time],.pure-group input[type=url],.pure-group input[type=week]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0}.pure-form-message,.pure-form-message-inline{display:block;font-size:.75em;padding:.2em 0 .8em}}.pure-menu{box-sizing:border-box}.pure-menu-fixed{position:fixed;left:0;top:0;z-index:3}.pure-menu-item,.pure-menu-list{position:relative}.pure-menu-list{list-style:none;margin:0;padding:0}.pure-menu-item{padding:0;margin:0;height:100%}.pure-menu-heading,.pure-menu-link{display:block;text-decoration:none;white-space:nowrap}.pure-menu-horizontal{width:100%;white-space:nowrap}.pure-menu-horizontal .pure-menu-list{display:inline-block}.pure-menu-horizontal .pure-menu-heading,.pure-menu-horizontal .pure-menu-item,.pure-menu-horizontal .pure-menu-separator{display:inline-block;vertical-align:middle}.pure-menu-item .pure-menu-item{display:block}.pure-menu-children{display:none;position:absolute;left:100%;top:0;margin:0;padding:0;z-index:3}.pure-menu-horizontal .pure-menu-children{left:0;top:auto;width:inherit}.pure-menu-active>.pure-menu-children,.pure-menu-allow-hover:hover>.pure-menu-children{display:block;position:absolute}.pure-menu-has-children>.pure-menu-link:after{padding-left:.5em;content:"▸";font-size:small}.pure-menu-horizontal .pure-menu-has-children>.pure-menu-link:after{content:"▾"}.pure-menu-scrollable{overflow-y:scroll;overflow-x:hidden}.pure-menu-scrollable .pure-menu-list{display:block}.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list{display:inline-block}.pure-menu-horizontal.pure-menu-scrollable{white-space:nowrap;overflow-y:hidden;overflow-x:auto;padding:.5em 0}.pure-menu-horizontal .pure-menu-children .pure-menu-separator,.pure-menu-separator{background-color:#ccc;height:1px;margin:.3em 0}.pure-menu-horizontal .pure-menu-separator{width:1px;height:1.3em;margin:0 .3em}.pure-menu-horizontal .pure-menu-children .pure-menu-separator{display:block;width:auto}.pure-menu-heading{text-transform:uppercase;color:#565d64}.pure-menu-link{color:#777}.pure-menu-children{background-color:#fff}.pure-menu-heading,.pure-menu-link{padding:.5em 1em}.pure-menu-disabled{opacity:.5}.pure-menu-disabled .pure-menu-link:hover{background-color:transparent;cursor:default}.pure-menu-active>.pure-menu-link,.pure-menu-link:focus,.pure-menu-link:hover{background-color:#eee}.pure-menu-selected>.pure-menu-link,.pure-menu-selected>.pure-menu-link:visited{color:#000}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.5em 1em}.pure-table thead{background-color:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child>td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child>td{border-bottom-width:0}html,body{height:100%;margin:0;padding:0}#app,div.main{width:100%;height:100%}div.overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:998;background-color:#010101cc}form.login{position:relative;margin:20% auto;padding:20px;width:300px;background-color:#ddd;border-radius:5px;text-align:right}form.login>input{margin:4px}div.users{height:100%;width:240px;background-color:#444;float:right}div.users>div{color:#aaa;margin:2px;padding:4px;cursor:pointer}div.users>div.is-selected{background-color:#777}div.messages{width:calc(100% - 240px);height:calc(100% - 90px);float:left;display:flex;flex-direction:column-reverse}div.messages>div{margin:4px 200px 4px 4px;border:solid #AAA 1px;border-radius:5px;background-color:#b6dcf2;padding:6px}div.messages>div.from-self{margin-right:4px;margin-left:200px}div.message-form{padding:5px;height:80px;width:calc(100% - 250px);float:left}div.message-form *{height:100%}div.message-form>form>div:nth-child(2){float:right;width:80px}div.message-form>form>div:nth-child(1){float:left;width:calc(100% - 80px)}div.messages>div>div.header{color:#777;font-size:.7em}div.app-log{position:absolute;padding:10px;width:500px;height:80px;top:0;left:calc(50% - 250px);background-color:#ddd;overflow-y:scroll;scrollbar-width:thin;scrollbar-color:#999 #DDD;display:flex;flex-direction:column-reverse;font-size:10px;z-index:998}div.app-log>div.error{color:#b33}div.app-log>div.warning{color:#bb3}div.app-log>div.info{color:#33b}div.app-log>div>span{display:inline-block;width:120px;margin:2px;overflow:hidden}div.app-log>div>span:nth-child(2){width:80px}div.app-log>div>span:nth-child(3){width:268px} diff --git a/src/Web1.Sse.ChatApi/wwwroot/web1-sse-chat-app.js b/src/Web1.Sse.ChatApi/wwwroot/web1-sse-chat-app.js new file mode 100644 index 0000000..577fc98 --- /dev/null +++ b/src/Web1.Sse.ChatApi/wwwroot/web1-sse-chat-app.js @@ -0,0 +1,5804 @@ +(function() { + const t = document.createElement("link").relList; + if (t && t.supports && t.supports("modulepreload")) + return; + for (const r of document.querySelectorAll('link[rel="modulepreload"]')) + o(r); + new MutationObserver((r) => { + for (const i of r) + if (i.type === "childList") + for (const s of i.addedNodes) + s.tagName === "LINK" && s.rel === "modulepreload" && o(s); + }).observe(document, { childList: !0, subtree: !0 }); + function n(r) { + const i = {}; + return r.integrity && (i.integrity = r.integrity), r.referrerPolicy && (i.referrerPolicy = r.referrerPolicy), r.crossOrigin === "use-credentials" ? i.credentials = "include" : r.crossOrigin === "anonymous" ? i.credentials = "omit" : i.credentials = "same-origin", i; + } + function o(r) { + if (r.ep) + return; + r.ep = !0; + const i = n(r); + fetch(r.href, i); + } +})(); +var li = {}; +/** +* @vue/shared v3.4.21 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/ +function Xe(e, t) { + const n = new Set(e.split(",")); + return t ? (o) => n.has(o.toLowerCase()) : (o) => n.has(o); +} +const X = li.NODE_ENV !== "production" ? Object.freeze({}) : {}, It = li.NODE_ENV !== "production" ? Object.freeze([]) : [], le = () => { +}, Vs = () => !1, un = (e) => e.charCodeAt(0) === 111 && e.charCodeAt(1) === 110 && // uppercase letter +(e.charCodeAt(2) > 122 || e.charCodeAt(2) < 97), Mn = (e) => e.startsWith("onUpdate:"), ne = Object.assign, Uo = (e, t) => { + const n = e.indexOf(t); + n > -1 && e.splice(n, 1); +}, Ss = Object.prototype.hasOwnProperty, B = (e, t) => Ss.call(e, t), F = Array.isArray, gt = (e) => Wn(e) === "[object Map]", ci = (e) => Wn(e) === "[object Set]", P = (e) => typeof e == "function", oe = (e) => typeof e == "string", Lt = (e) => typeof e == "symbol", Y = (e) => e !== null && typeof e == "object", Ho = (e) => (Y(e) || P(e)) && P(e.then) && P(e.catch), ui = Object.prototype.toString, Wn = (e) => ui.call(e), ko = (e) => Wn(e).slice(8, -1), fi = (e) => Wn(e) === "[object Object]", Bo = (e) => oe(e) && e !== "NaN" && e[0] !== "-" && "" + parseInt(e, 10) === e, Yt = /* @__PURE__ */ Xe( + // the leading comma is intentional so empty string "" is also included + ",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted" +), Cs = /* @__PURE__ */ Xe( + "bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo" +), qn = (e) => { + const t = /* @__PURE__ */ Object.create(null); + return (n) => t[n] || (t[n] = e(n)); +}, Ts = /-(\w)/g, Rt = qn((e) => e.replace(Ts, (t, n) => n ? n.toUpperCase() : "")), $s = /\B([A-Z])/g, Je = qn( + (e) => e.replace($s, "-$1").toLowerCase() +), Gn = qn((e) => e.charAt(0).toUpperCase() + e.slice(1)), ht = qn((e) => e ? `on${Gn(e)}` : ""), lt = (e, t) => !Object.is(e, t), $t = (e, t) => { + for (let n = 0; n < e.length; n++) + e[n](t); +}, Rn = (e, t, n) => { + Object.defineProperty(e, t, { + configurable: !0, + enumerable: !1, + value: n + }); +}, vo = (e) => { + const t = parseFloat(e); + return isNaN(t) ? e : t; +}; +let Er; +const Ko = () => Er || (Er = typeof globalThis < "u" ? globalThis : typeof self < "u" ? self : typeof window < "u" ? window : typeof global < "u" ? global : {}); +function Wo(e) { + if (F(e)) { + const t = {}; + for (let n = 0; n < e.length; n++) { + const o = e[n], r = oe(o) ? Is(o) : Wo(o); + if (r) + for (const i in r) + t[i] = r[i]; + } + return t; + } else if (oe(e) || Y(e)) + return e; +} +const Fs = /;(?![^(]*\))/g, As = /:([^]+)/, Ps = /\/\*[^]*?\*\//g; +function Is(e) { + const t = {}; + return e.replace(Ps, "").split(Fs).forEach((n) => { + if (n) { + const o = n.split(As); + o.length > 1 && (t[o[0].trim()] = o[1].trim()); + } + }), t; +} +function Ut(e) { + let t = ""; + if (oe(e)) + t = e; + else if (F(e)) + for (let n = 0; n < e.length; n++) { + const o = Ut(e[n]); + o && (t += o + " "); + } + else if (Y(e)) + for (const n in e) + e[n] && (t += n + " "); + return t.trim(); +} +const Ms = "html,body,base,head,link,meta,style,title,address,article,aside,footer,header,hgroup,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,summary,template,blockquote,iframe,tfoot", Rs = "svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,feDistantLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,text,textPath,title,tspan,unknown,use,view", js = "annotation,annotation-xml,maction,maligngroup,malignmark,math,menclose,merror,mfenced,mfrac,mfraction,mglyph,mi,mlabeledtr,mlongdiv,mmultiscripts,mn,mo,mover,mpadded,mphantom,mprescripts,mroot,mrow,ms,mscarries,mscarry,msgroup,msline,mspace,msqrt,msrow,mstack,mstyle,msub,msubsup,msup,mtable,mtd,mtext,mtr,munder,munderover,none,semantics", Ls = /* @__PURE__ */ Xe(Ms), Us = /* @__PURE__ */ Xe(Rs), Hs = /* @__PURE__ */ Xe(js), ks = "itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly", Bs = /* @__PURE__ */ Xe(ks); +function ai(e) { + return !!e || e === ""; +} +const it = (e) => oe(e) ? e : e == null ? "" : F(e) || Y(e) && (e.toString === ui || !P(e.toString)) ? JSON.stringify(e, di, 2) : String(e), di = (e, t) => t && t.__v_isRef ? di(e, t.value) : gt(t) ? { + [`Map(${t.size})`]: [...t.entries()].reduce( + (n, [o, r], i) => (n[fo(o, i) + " =>"] = r, n), + {} + ) +} : ci(t) ? { + [`Set(${t.size})`]: [...t.values()].map((n) => fo(n)) +} : Lt(t) ? fo(t) : Y(t) && !F(t) && !fi(t) ? String(t) : t, fo = (e, t = "") => { + var n; + return Lt(e) ? `Symbol(${(n = e.description) != null ? n : t})` : e; +}; +var ce = {}; +function Ye(e, ...t) { + console.warn(`[Vue warn] ${e}`, ...t); +} +let Oe; +class Ks { + constructor(t = !1) { + this.detached = t, this._active = !0, this.effects = [], this.cleanups = [], this.parent = Oe, !t && Oe && (this.index = (Oe.scopes || (Oe.scopes = [])).push( + this + ) - 1); + } + get active() { + return this._active; + } + run(t) { + if (this._active) { + const n = Oe; + try { + return Oe = this, t(); + } finally { + Oe = n; + } + } else + ce.NODE_ENV !== "production" && Ye("cannot run an inactive effect scope."); + } + /** + * This should only be called on non-detached scopes + * @internal + */ + on() { + Oe = this; + } + /** + * This should only be called on non-detached scopes + * @internal + */ + off() { + Oe = this.parent; + } + stop(t) { + if (this._active) { + let n, o; + for (n = 0, o = this.effects.length; n < o; n++) + this.effects[n].stop(); + for (n = 0, o = this.cleanups.length; n < o; n++) + this.cleanups[n](); + if (this.scopes) + for (n = 0, o = this.scopes.length; n < o; n++) + this.scopes[n].stop(!0); + if (!this.detached && this.parent && !t) { + const r = this.parent.scopes.pop(); + r && r !== this && (this.parent.scopes[this.index] = r, r.index = this.index); + } + this.parent = void 0, this._active = !1; + } + } +} +function Ws(e, t = Oe) { + t && t.active && t.effects.push(e); +} +function qo() { + return Oe; +} +function qs(e) { + Oe ? Oe.cleanups.push(e) : ce.NODE_ENV !== "production" && Ye( + "onScopeDispose() is called when there is no active effect scope to be associated with." + ); +} +let _t; +class Go { + constructor(t, n, o, r) { + this.fn = t, this.trigger = n, this.scheduler = o, this.active = !0, this.deps = [], this._dirtyLevel = 4, this._trackId = 0, this._runnings = 0, this._shouldSchedule = !1, this._depsLength = 0, Ws(this, r); + } + get dirty() { + if (this._dirtyLevel === 2 || this._dirtyLevel === 3) { + this._dirtyLevel = 1, ft(); + for (let t = 0; t < this._depsLength; t++) { + const n = this.deps[t]; + if (n.computed && (Gs(n.computed), this._dirtyLevel >= 4)) + break; + } + this._dirtyLevel === 1 && (this._dirtyLevel = 0), at(); + } + return this._dirtyLevel >= 4; + } + set dirty(t) { + this._dirtyLevel = t ? 4 : 0; + } + run() { + if (this._dirtyLevel = 0, !this.active) + return this.fn(); + let t = st, n = _t; + try { + return st = !0, _t = this, this._runnings++, yr(this), this.fn(); + } finally { + br(this), this._runnings--, _t = n, st = t; + } + } + stop() { + var t; + this.active && (yr(this), br(this), (t = this.onStop) == null || t.call(this), this.active = !1); + } +} +function Gs(e) { + return e.value; +} +function yr(e) { + e._trackId++, e._depsLength = 0; +} +function br(e) { + if (e.deps.length > e._depsLength) { + for (let t = e._depsLength; t < e.deps.length; t++) + pi(e.deps[t], e); + e.deps.length = e._depsLength; + } +} +function pi(e, t) { + const n = e.get(t); + n !== void 0 && t._trackId !== n && (e.delete(t), e.size === 0 && e.cleanup()); +} +let st = !0, No = 0; +const hi = []; +function ft() { + hi.push(st), st = !1; +} +function at() { + const e = hi.pop(); + st = e === void 0 ? !0 : e; +} +function zo() { + No++; +} +function Jo() { + for (No--; !No && Oo.length; ) + Oo.shift()(); +} +function mi(e, t, n) { + var o; + if (t.get(e) !== e._trackId) { + t.set(e, e._trackId); + const r = e.deps[e._depsLength]; + r !== t ? (r && pi(r, e), e.deps[e._depsLength++] = t) : e._depsLength++, ce.NODE_ENV !== "production" && ((o = e.onTrack) == null || o.call(e, ne({ effect: e }, n))); + } +} +const Oo = []; +function gi(e, t, n) { + var o; + zo(); + for (const r of e.keys()) { + let i; + r._dirtyLevel < t && (i ?? (i = e.get(r) === r._trackId)) && (r._shouldSchedule || (r._shouldSchedule = r._dirtyLevel === 0), r._dirtyLevel = t), r._shouldSchedule && (i ?? (i = e.get(r) === r._trackId)) && (ce.NODE_ENV !== "production" && ((o = r.onTrigger) == null || o.call(r, ne({ effect: r }, n))), r.trigger(), (!r._runnings || r.allowRecurse) && r._dirtyLevel !== 2 && (r._shouldSchedule = !1, r.scheduler && Oo.push(r.scheduler))); + } + Jo(); +} +const _i = (e, t) => { + const n = /* @__PURE__ */ new Map(); + return n.cleanup = e, n.computed = t, n; +}, jn = /* @__PURE__ */ new WeakMap(), Et = Symbol(ce.NODE_ENV !== "production" ? "iterate" : ""), wo = Symbol(ce.NODE_ENV !== "production" ? "Map key iterate" : ""); +function de(e, t, n) { + if (st && _t) { + let o = jn.get(e); + o || jn.set(e, o = /* @__PURE__ */ new Map()); + let r = o.get(n); + r || o.set(n, r = _i(() => o.delete(n))), mi( + _t, + r, + ce.NODE_ENV !== "production" ? { + target: e, + type: t, + key: n + } : void 0 + ); + } +} +function ke(e, t, n, o, r, i) { + const s = jn.get(e); + if (!s) + return; + let l = []; + if (t === "clear") + l = [...s.values()]; + else if (n === "length" && F(e)) { + const u = Number(o); + s.forEach((f, h) => { + (h === "length" || !Lt(h) && h >= u) && l.push(f); + }); + } else + switch (n !== void 0 && l.push(s.get(n)), t) { + case "add": + F(e) ? Bo(n) && l.push(s.get("length")) : (l.push(s.get(Et)), gt(e) && l.push(s.get(wo))); + break; + case "delete": + F(e) || (l.push(s.get(Et)), gt(e) && l.push(s.get(wo))); + break; + case "set": + gt(e) && l.push(s.get(Et)); + break; + } + zo(); + for (const u of l) + u && gi( + u, + 4, + ce.NODE_ENV !== "production" ? { + target: e, + type: t, + key: n, + newValue: o, + oldValue: r, + oldTarget: i + } : void 0 + ); + Jo(); +} +function zs(e, t) { + var n; + return (n = jn.get(e)) == null ? void 0 : n.get(t); +} +const Js = /* @__PURE__ */ Xe("__proto__,__v_isRef,__isVue"), Ei = new Set( + /* @__PURE__ */ Object.getOwnPropertyNames(Symbol).filter((e) => e !== "arguments" && e !== "caller").map((e) => Symbol[e]).filter(Lt) +), vr = /* @__PURE__ */ Ys(); +function Ys() { + const e = {}; + return ["includes", "indexOf", "lastIndexOf"].forEach((t) => { + e[t] = function(...n) { + const o = L(this); + for (let i = 0, s = this.length; i < s; i++) + de(o, "get", i + ""); + const r = o[t](...n); + return r === -1 || r === !1 ? o[t](...n.map(L)) : r; + }; + }), ["push", "pop", "shift", "unshift", "splice"].forEach((t) => { + e[t] = function(...n) { + ft(), zo(); + const o = L(this)[t].apply(this, n); + return Jo(), at(), o; + }; + }), e; +} +function Xs(e) { + const t = L(this); + return de(t, "has", e), t.hasOwnProperty(e); +} +class yi { + constructor(t = !1, n = !1) { + this._isReadonly = t, this._isShallow = n; + } + get(t, n, o) { + const r = this._isReadonly, i = this._isShallow; + if (n === "__v_isReactive") + return !r; + if (n === "__v_isReadonly") + return r; + if (n === "__v_isShallow") + return i; + if (n === "__v_raw") + return o === (r ? i ? xi : Di : i ? wi : Oi).get(t) || // receiver is not the reactive proxy, but has the same prototype + // this means the reciever is a user proxy of the reactive proxy + Object.getPrototypeOf(t) === Object.getPrototypeOf(o) ? t : void 0; + const s = F(t); + if (!r) { + if (s && B(vr, n)) + return Reflect.get(vr, n, o); + if (n === "hasOwnProperty") + return Xs; + } + const l = Reflect.get(t, n, o); + return (Lt(n) ? Ei.has(n) : Js(n)) || (r || de(t, "get", n), i) ? l : ie(l) ? s && Bo(n) ? l : l.value : Y(l) ? r ? Dt(l) : Xo(l) : l; + } +} +class bi extends yi { + constructor(t = !1) { + super(!1, t); + } + set(t, n, o, r) { + let i = t[n]; + if (!this._isShallow) { + const u = ct(i); + if (!bt(o) && !ct(o) && (i = L(i), o = L(o)), !F(t) && ie(i) && !ie(o)) + return u ? !1 : (i.value = o, !0); + } + const s = F(t) && Bo(n) ? Number(n) < t.length : B(t, n), l = Reflect.set(t, n, o, r); + return t === L(r) && (s ? lt(o, i) && ke(t, "set", n, o, i) : ke(t, "add", n, o)), l; + } + deleteProperty(t, n) { + const o = B(t, n), r = t[n], i = Reflect.deleteProperty(t, n); + return i && o && ke(t, "delete", n, void 0, r), i; + } + has(t, n) { + const o = Reflect.has(t, n); + return (!Lt(n) || !Ei.has(n)) && de(t, "has", n), o; + } + ownKeys(t) { + return de( + t, + "iterate", + F(t) ? "length" : Et + ), Reflect.ownKeys(t); + } +} +class vi extends yi { + constructor(t = !1) { + super(!0, t); + } + set(t, n) { + return ce.NODE_ENV !== "production" && Ye( + `Set operation on key "${String(n)}" failed: target is readonly.`, + t + ), !0; + } + deleteProperty(t, n) { + return ce.NODE_ENV !== "production" && Ye( + `Delete operation on key "${String(n)}" failed: target is readonly.`, + t + ), !0; + } +} +const Zs = /* @__PURE__ */ new bi(), Qs = /* @__PURE__ */ new vi(), el = /* @__PURE__ */ new bi( + !0 +), tl = /* @__PURE__ */ new vi(!0), Yo = (e) => e, zn = (e) => Reflect.getPrototypeOf(e); +function En(e, t, n = !1, o = !1) { + e = e.__v_raw; + const r = L(e), i = L(t); + n || (lt(t, i) && de(r, "get", t), de(r, "get", i)); + const { has: s } = zn(r), l = o ? Yo : n ? Zo : on; + if (s.call(r, t)) + return l(e.get(t)); + if (s.call(r, i)) + return l(e.get(i)); + e !== r && e.get(t); +} +function yn(e, t = !1) { + const n = this.__v_raw, o = L(n), r = L(e); + return t || (lt(e, r) && de(o, "has", e), de(o, "has", r)), e === r ? n.has(e) : n.has(e) || n.has(r); +} +function bn(e, t = !1) { + return e = e.__v_raw, !t && de(L(e), "iterate", Et), Reflect.get(e, "size", e); +} +function Nr(e) { + e = L(e); + const t = L(this); + return zn(t).has.call(t, e) || (t.add(e), ke(t, "add", e, e)), this; +} +function Or(e, t) { + t = L(t); + const n = L(this), { has: o, get: r } = zn(n); + let i = o.call(n, e); + i ? ce.NODE_ENV !== "production" && Ni(n, o, e) : (e = L(e), i = o.call(n, e)); + const s = r.call(n, e); + return n.set(e, t), i ? lt(t, s) && ke(n, "set", e, t, s) : ke(n, "add", e, t), this; +} +function wr(e) { + const t = L(this), { has: n, get: o } = zn(t); + let r = n.call(t, e); + r ? ce.NODE_ENV !== "production" && Ni(t, n, e) : (e = L(e), r = n.call(t, e)); + const i = o ? o.call(t, e) : void 0, s = t.delete(e); + return r && ke(t, "delete", e, void 0, i), s; +} +function Dr() { + const e = L(this), t = e.size !== 0, n = ce.NODE_ENV !== "production" ? gt(e) ? new Map(e) : new Set(e) : void 0, o = e.clear(); + return t && ke(e, "clear", void 0, void 0, n), o; +} +function vn(e, t) { + return function(o, r) { + const i = this, s = i.__v_raw, l = L(s), u = t ? Yo : e ? Zo : on; + return !e && de(l, "iterate", Et), s.forEach((f, h) => o.call(r, u(f), u(h), i)); + }; +} +function Nn(e, t, n) { + return function(...o) { + const r = this.__v_raw, i = L(r), s = gt(i), l = e === "entries" || e === Symbol.iterator && s, u = e === "keys" && s, f = r[e](...o), h = n ? Yo : t ? Zo : on; + return !t && de( + i, + "iterate", + u ? wo : Et + ), { + // iterator protocol + next() { + const { value: a, done: g } = f.next(); + return g ? { value: a, done: g } : { + value: l ? [h(a[0]), h(a[1])] : h(a), + done: g + }; + }, + // iterable protocol + [Symbol.iterator]() { + return this; + } + }; + }; +} +function et(e) { + return function(...t) { + if (ce.NODE_ENV !== "production") { + const n = t[0] ? `on key "${t[0]}" ` : ""; + Ye( + `${Gn(e)} operation ${n}failed: target is readonly.`, + L(this) + ); + } + return e === "delete" ? !1 : e === "clear" ? void 0 : this; + }; +} +function nl() { + const e = { + get(i) { + return En(this, i); + }, + get size() { + return bn(this); + }, + has: yn, + add: Nr, + set: Or, + delete: wr, + clear: Dr, + forEach: vn(!1, !1) + }, t = { + get(i) { + return En(this, i, !1, !0); + }, + get size() { + return bn(this); + }, + has: yn, + add: Nr, + set: Or, + delete: wr, + clear: Dr, + forEach: vn(!1, !0) + }, n = { + get(i) { + return En(this, i, !0); + }, + get size() { + return bn(this, !0); + }, + has(i) { + return yn.call(this, i, !0); + }, + add: et("add"), + set: et("set"), + delete: et("delete"), + clear: et("clear"), + forEach: vn(!0, !1) + }, o = { + get(i) { + return En(this, i, !0, !0); + }, + get size() { + return bn(this, !0); + }, + has(i) { + return yn.call(this, i, !0); + }, + add: et("add"), + set: et("set"), + delete: et("delete"), + clear: et("clear"), + forEach: vn(!0, !0) + }; + return ["keys", "values", "entries", Symbol.iterator].forEach((i) => { + e[i] = Nn( + i, + !1, + !1 + ), n[i] = Nn( + i, + !0, + !1 + ), t[i] = Nn( + i, + !1, + !0 + ), o[i] = Nn( + i, + !0, + !0 + ); + }), [ + e, + n, + t, + o + ]; +} +const [ + ol, + rl, + il, + sl +] = /* @__PURE__ */ nl(); +function Jn(e, t) { + const n = t ? e ? sl : il : e ? rl : ol; + return (o, r, i) => r === "__v_isReactive" ? !e : r === "__v_isReadonly" ? e : r === "__v_raw" ? o : Reflect.get( + B(n, r) && r in o ? n : o, + r, + i + ); +} +const ll = { + get: /* @__PURE__ */ Jn(!1, !1) +}, cl = { + get: /* @__PURE__ */ Jn(!1, !0) +}, ul = { + get: /* @__PURE__ */ Jn(!0, !1) +}, fl = { + get: /* @__PURE__ */ Jn(!0, !0) +}; +function Ni(e, t, n) { + const o = L(n); + if (o !== n && t.call(e, o)) { + const r = ko(e); + Ye( + `Reactive ${r} contains both the raw and reactive versions of the same object${r === "Map" ? " as keys" : ""}, which can lead to inconsistencies. Avoid differentiating between the raw and reactive versions of an object and only use the reactive version if possible.` + ); + } +} +const Oi = /* @__PURE__ */ new WeakMap(), wi = /* @__PURE__ */ new WeakMap(), Di = /* @__PURE__ */ new WeakMap(), xi = /* @__PURE__ */ new WeakMap(); +function al(e) { + switch (e) { + case "Object": + case "Array": + return 1; + case "Map": + case "Set": + case "WeakMap": + case "WeakSet": + return 2; + default: + return 0; + } +} +function dl(e) { + return e.__v_skip || !Object.isExtensible(e) ? 0 : al(ko(e)); +} +function Xo(e) { + return ct(e) ? e : Yn( + e, + !1, + Zs, + ll, + Oi + ); +} +function pl(e) { + return Yn( + e, + !1, + el, + cl, + wi + ); +} +function Dt(e) { + return Yn( + e, + !0, + Qs, + ul, + Di + ); +} +function Pt(e) { + return Yn( + e, + !0, + tl, + fl, + xi + ); +} +function Yn(e, t, n, o, r) { + if (!Y(e)) + return ce.NODE_ENV !== "production" && Ye(`value cannot be made reactive: ${String(e)}`), e; + if (e.__v_raw && !(t && e.__v_isReactive)) + return e; + const i = r.get(e); + if (i) + return i; + const s = dl(e); + if (s === 0) + return e; + const l = new Proxy( + e, + s === 2 ? o : n + ); + return r.set(e, l), l; +} +function yt(e) { + return ct(e) ? yt(e.__v_raw) : !!(e && e.__v_isReactive); +} +function ct(e) { + return !!(e && e.__v_isReadonly); +} +function bt(e) { + return !!(e && e.__v_isShallow); +} +function Do(e) { + return yt(e) || ct(e); +} +function L(e) { + const t = e && e.__v_raw; + return t ? L(t) : e; +} +function Vi(e) { + return Object.isExtensible(e) && Rn(e, "__v_skip", !0), e; +} +const on = (e) => Y(e) ? Xo(e) : e, Zo = (e) => Y(e) ? Dt(e) : e, hl = "Computed is still dirty after getter evaluation, likely because a computed is mutating its own dependency in its getter. State mutations in computed getters should be avoided. Check the docs for more details: https://vuejs.org/guide/essentials/computed.html#getters-should-be-side-effect-free"; +class Si { + constructor(t, n, o, r) { + this.getter = t, this._setter = n, this.dep = void 0, this.__v_isRef = !0, this.__v_isReadonly = !1, this.effect = new Go( + () => t(this._value), + () => Xt( + this, + this.effect._dirtyLevel === 2 ? 2 : 3 + ) + ), this.effect.computed = this, this.effect.active = this._cacheable = !r, this.__v_isReadonly = o; + } + get value() { + const t = L(this); + return (!t._cacheable || t.effect.dirty) && lt(t._value, t._value = t.effect.run()) && Xt(t, 4), Qo(t), t.effect._dirtyLevel >= 2 && (ce.NODE_ENV !== "production" && this._warnRecursive && Ye(hl, ` + +getter: `, this.getter), Xt(t, 2)), t._value; + } + set value(t) { + this._setter(t); + } + // #region polyfill _dirty for backward compatibility third party code for Vue <= 3.3.x + get _dirty() { + return this.effect.dirty; + } + set _dirty(t) { + this.effect.dirty = t; + } + // #endregion +} +function ml(e, t, n = !1) { + let o, r; + const i = P(e); + i ? (o = e, r = ce.NODE_ENV !== "production" ? () => { + Ye("Write operation failed: computed value is readonly"); + } : le) : (o = e.get, r = e.set); + const s = new Si(o, r, i || !r, n); + return ce.NODE_ENV !== "production" && t && !n && (s.effect.onTrack = t.onTrack, s.effect.onTrigger = t.onTrigger), s; +} +function Qo(e) { + var t; + st && _t && (e = L(e), mi( + _t, + (t = e.dep) != null ? t : e.dep = _i( + () => e.dep = void 0, + e instanceof Si ? e : void 0 + ), + ce.NODE_ENV !== "production" ? { + target: e, + type: "get", + key: "value" + } : void 0 + )); +} +function Xt(e, t = 4, n) { + e = L(e); + const o = e.dep; + o && gi( + o, + t, + ce.NODE_ENV !== "production" ? { + target: e, + type: "set", + key: "value", + newValue: n + } : void 0 + ); +} +function ie(e) { + return !!(e && e.__v_isRef === !0); +} +function ge(e) { + return Ci(e, !1); +} +function Vn(e) { + return Ci(e, !0); +} +function Ci(e, t) { + return ie(e) ? e : new gl(e, t); +} +class gl { + constructor(t, n) { + this.__v_isShallow = n, this.dep = void 0, this.__v_isRef = !0, this._rawValue = n ? t : L(t), this._value = n ? t : on(t); + } + get value() { + return Qo(this), this._value; + } + set value(t) { + const n = this.__v_isShallow || bt(t) || ct(t); + t = n ? t : L(t), lt(t, this._rawValue) && (this._rawValue = t, this._value = n ? t : on(t), Xt(this, 4, t)); + } +} +function fn(e) { + return ie(e) ? e.value : e; +} +const _l = { + get: (e, t, n) => fn(Reflect.get(e, t, n)), + set: (e, t, n, o) => { + const r = e[t]; + return ie(r) && !ie(n) ? (r.value = n, !0) : Reflect.set(e, t, n, o); + } +}; +function Ti(e) { + return yt(e) ? e : new Proxy(e, _l); +} +class El { + constructor(t) { + this.dep = void 0, this.__v_isRef = !0; + const { get: n, set: o } = t( + () => Qo(this), + () => Xt(this) + ); + this._get = n, this._set = o; + } + get value() { + return this._get(); + } + set value(t) { + this._set(t); + } +} +function yl(e) { + return new El(e); +} +class bl { + constructor(t, n, o) { + this._object = t, this._key = n, this._defaultValue = o, this.__v_isRef = !0; + } + get value() { + const t = this._object[this._key]; + return t === void 0 ? this._defaultValue : t; + } + set value(t) { + this._object[this._key] = t; + } + get dep() { + return zs(L(this._object), this._key); + } +} +class vl { + constructor(t) { + this._getter = t, this.__v_isRef = !0, this.__v_isReadonly = !0; + } + get value() { + return this._getter(); + } +} +function Nl(e, t, n) { + return ie(e) ? e : P(e) ? new vl(e) : Y(e) && arguments.length > 1 ? Ol(e, t, n) : ge(e); +} +function Ol(e, t, n) { + const o = e[t]; + return ie(o) ? o : new bl(e, t, n); +} +var p = {}; +const vt = []; +function Sn(e) { + vt.push(e); +} +function Cn() { + vt.pop(); +} +function w(e, ...t) { + ft(); + const n = vt.length ? vt[vt.length - 1].component : null, o = n && n.appContext.config.warnHandler, r = wl(); + if (o) + ze( + o, + n, + 11, + [ + e + t.map((i) => { + var s, l; + return (l = (s = i.toString) == null ? void 0 : s.call(i)) != null ? l : JSON.stringify(i); + }).join(""), + n && n.proxy, + r.map( + ({ vnode: i }) => `at <${oo(n, i.type)}>` + ).join(` +`), + r + ] + ); + else { + const i = [`[Vue warn]: ${e}`, ...t]; + r.length && i.push(` +`, ...Dl(r)), console.warn(...i); + } + at(); +} +function wl() { + let e = vt[vt.length - 1]; + if (!e) + return []; + const t = []; + for (; e; ) { + const n = t[0]; + n && n.vnode === e ? n.recurseCount++ : t.push({ + vnode: e, + recurseCount: 0 + }); + const o = e.component && e.component.parent; + e = o && o.vnode; + } + return t; +} +function Dl(e) { + const t = []; + return e.forEach((n, o) => { + t.push(...o === 0 ? [] : [` +`], ...xl(n)); + }), t; +} +function xl({ vnode: e, recurseCount: t }) { + const n = t > 0 ? `... (${t} recursive calls)` : "", o = e.component ? e.component.parent == null : !1, r = ` at <${oo( + e.component, + e.type, + o + )}`, i = ">" + n; + return e.props ? [r, ...Vl(e.props), i] : [r + i]; +} +function Vl(e) { + const t = [], n = Object.keys(e); + return n.slice(0, 3).forEach((o) => { + t.push(...$i(o, e[o])); + }), n.length > 3 && t.push(" ..."), t; +} +function $i(e, t, n) { + return oe(t) ? (t = JSON.stringify(t), n ? t : [`${e}=${t}`]) : typeof t == "number" || typeof t == "boolean" || t == null ? n ? t : [`${e}=${t}`] : ie(t) ? (t = $i(e, L(t.value), !0), n ? t : [`${e}=Ref<`, t, ">"]) : P(t) ? [`${e}=fn${t.name ? `<${t.name}>` : ""}`] : (t = L(t), n ? t : [`${e}=`, t]); +} +const er = { + sp: "serverPrefetch hook", + bc: "beforeCreate hook", + c: "created hook", + bm: "beforeMount hook", + m: "mounted hook", + bu: "beforeUpdate hook", + u: "updated", + bum: "beforeUnmount hook", + um: "unmounted hook", + a: "activated hook", + da: "deactivated hook", + ec: "errorCaptured hook", + rtc: "renderTracked hook", + rtg: "renderTriggered hook", + 0: "setup function", + 1: "render function", + 2: "watcher getter", + 3: "watcher callback", + 4: "watcher cleanup function", + 5: "native event handler", + 6: "component event handler", + 7: "vnode hook", + 8: "directive hook", + 9: "transition hook", + 10: "app errorHandler", + 11: "app warnHandler", + 12: "ref function", + 13: "async component loader", + 14: "scheduler flush. This is likely a Vue internals bug. Please open an issue at https://github.com/vuejs/core ." +}; +function ze(e, t, n, o) { + try { + return o ? e(...o) : e(); + } catch (r) { + an(r, t, n); + } +} +function Me(e, t, n, o) { + if (P(e)) { + const i = ze(e, t, n, o); + return i && Ho(i) && i.catch((s) => { + an(s, t, n); + }), i; + } + const r = []; + for (let i = 0; i < e.length; i++) + r.push(Me(e[i], t, n, o)); + return r; +} +function an(e, t, n, o = !0) { + const r = t ? t.vnode : null; + if (t) { + let i = t.parent; + const s = t.proxy, l = p.NODE_ENV !== "production" ? er[n] : `https://vuejs.org/error-reference/#runtime-${n}`; + for (; i; ) { + const f = i.ec; + if (f) { + for (let h = 0; h < f.length; h++) + if (f[h](e, s, l) === !1) + return; + } + i = i.parent; + } + const u = t.appContext.config.errorHandler; + if (u) { + ze( + u, + null, + 10, + [e, s, l] + ); + return; + } + } + Sl(e, n, r, o); +} +function Sl(e, t, n, o = !0) { + if (p.NODE_ENV !== "production") { + const r = er[t]; + if (n && Sn(n), w(`Unhandled error${r ? ` during execution of ${r}` : ""}`), n && Cn(), o) + throw e; + console.error(e); + } else + console.error(e); +} +let rn = !1, xo = !1; +const me = []; +let Ue = 0; +const Mt = []; +let Ge = null, tt = 0; +const Fi = /* @__PURE__ */ Promise.resolve(); +let tr = null; +const Cl = 100; +function nr(e) { + const t = tr || Fi; + return e ? t.then(this ? e.bind(this) : e) : t; +} +function Tl(e) { + let t = Ue + 1, n = me.length; + for (; t < n; ) { + const o = t + n >>> 1, r = me[o], i = sn(r); + i < e || i === e && r.pre ? t = o + 1 : n = o; + } + return t; +} +function Xn(e) { + (!me.length || !me.includes( + e, + rn && e.allowRecurse ? Ue + 1 : Ue + )) && (e.id == null ? me.push(e) : me.splice(Tl(e.id), 0, e), Ai()); +} +function Ai() { + !rn && !xo && (xo = !0, tr = Fi.then(Mi)); +} +function $l(e) { + const t = me.indexOf(e); + t > Ue && me.splice(t, 1); +} +function Pi(e) { + F(e) ? Mt.push(...e) : (!Ge || !Ge.includes( + e, + e.allowRecurse ? tt + 1 : tt + )) && Mt.push(e), Ai(); +} +function xr(e, t, n = rn ? Ue + 1 : 0) { + for (p.NODE_ENV !== "production" && (t = t || /* @__PURE__ */ new Map()); n < me.length; n++) { + const o = me[n]; + if (o && o.pre) { + if (e && o.id !== e.uid || p.NODE_ENV !== "production" && or(t, o)) + continue; + me.splice(n, 1), n--, o(); + } + } +} +function Ii(e) { + if (Mt.length) { + const t = [...new Set(Mt)].sort( + (n, o) => sn(n) - sn(o) + ); + if (Mt.length = 0, Ge) { + Ge.push(...t); + return; + } + for (Ge = t, p.NODE_ENV !== "production" && (e = e || /* @__PURE__ */ new Map()), tt = 0; tt < Ge.length; tt++) + p.NODE_ENV !== "production" && or(e, Ge[tt]) || Ge[tt](); + Ge = null, tt = 0; + } +} +const sn = (e) => e.id == null ? 1 / 0 : e.id, Fl = (e, t) => { + const n = sn(e) - sn(t); + if (n === 0) { + if (e.pre && !t.pre) + return -1; + if (t.pre && !e.pre) + return 1; + } + return n; +}; +function Mi(e) { + xo = !1, rn = !0, p.NODE_ENV !== "production" && (e = e || /* @__PURE__ */ new Map()), me.sort(Fl); + const t = p.NODE_ENV !== "production" ? (n) => or(e, n) : le; + try { + for (Ue = 0; Ue < me.length; Ue++) { + const n = me[Ue]; + if (n && n.active !== !1) { + if (p.NODE_ENV !== "production" && t(n)) + continue; + ze(n, null, 14); + } + } + } finally { + Ue = 0, me.length = 0, Ii(e), rn = !1, tr = null, (me.length || Mt.length) && Mi(e); + } +} +function or(e, t) { + if (!e.has(t)) + e.set(t, 1); + else { + const n = e.get(t); + if (n > Cl) { + const o = t.ownerInstance, r = o && ds(o.type); + return an( + `Maximum recursive updates exceeded${r ? ` in component <${r}>` : ""}. This means you have a reactive effect that is mutating its own dependencies and thus recursively triggering itself. Possible sources include component template, render function, updated hook or watcher source function.`, + null, + 10 + ), !0; + } else + e.set(t, n + 1); + } +} +let Nt = !1; +const Ft = /* @__PURE__ */ new Set(); +p.NODE_ENV !== "production" && (Ko().__VUE_HMR_RUNTIME__ = { + createRecord: ao(Ri), + rerender: ao(Il), + reload: ao(Ml) +}); +const xt = /* @__PURE__ */ new Map(); +function Al(e) { + const t = e.type.__hmrId; + let n = xt.get(t); + n || (Ri(t, e.type), n = xt.get(t)), n.instances.add(e); +} +function Pl(e) { + xt.get(e.type.__hmrId).instances.delete(e); +} +function Ri(e, t) { + return xt.has(e) ? !1 : (xt.set(e, { + initialDef: Zt(t), + instances: /* @__PURE__ */ new Set() + }), !0); +} +function Zt(e) { + return ps(e) ? e.__vccOpts : e; +} +function Il(e, t) { + const n = xt.get(e); + n && (n.initialDef.render = t, [...n.instances].forEach((o) => { + t && (o.render = t, Zt(o.type).render = t), o.renderCache = [], Nt = !0, o.effect.dirty = !0, o.update(), Nt = !1; + })); +} +function Ml(e, t) { + const n = xt.get(e); + if (!n) + return; + t = Zt(t), Vr(n.initialDef, t); + const o = [...n.instances]; + for (const r of o) { + const i = Zt(r.type); + Ft.has(i) || (i !== n.initialDef && Vr(i, t), Ft.add(i)), r.appContext.propsCache.delete(r.type), r.appContext.emitsCache.delete(r.type), r.appContext.optionsCache.delete(r.type), r.ceReload ? (Ft.add(i), r.ceReload(t.styles), Ft.delete(i)) : r.parent ? (r.parent.effect.dirty = !0, Xn(r.parent.update)) : r.appContext.reload ? r.appContext.reload() : typeof window < "u" ? window.location.reload() : console.warn( + "[HMR] Root or manually mounted instance modified. Full reload required." + ); + } + Pi(() => { + for (const r of o) + Ft.delete( + Zt(r.type) + ); + }); +} +function Vr(e, t) { + ne(e, t); + for (const n in e) + n !== "__file" && !(n in t) && delete e[n]; +} +function ao(e) { + return (t, n) => { + try { + return e(t, n); + } catch (o) { + console.error(o), console.warn( + "[HMR] Something went wrong during Vue component hot-reload. Full reload required." + ); + } + }; +} +let He, zt = [], Vo = !1; +function dn(e, ...t) { + He ? He.emit(e, ...t) : Vo || zt.push({ event: e, args: t }); +} +function ji(e, t) { + var n, o; + He = e, He ? (He.enabled = !0, zt.forEach(({ event: r, args: i }) => He.emit(r, ...i)), zt = []) : /* handle late devtools injection - only do this if we are in an actual */ /* browser environment to avoid the timer handle stalling test runner exit */ /* (#4815) */ typeof window < "u" && // some envs mock window but not fully + window.HTMLElement && // also exclude jsdom + !((o = (n = window.navigator) == null ? void 0 : n.userAgent) != null && o.includes("jsdom")) ? ((t.__VUE_DEVTOOLS_HOOK_REPLAY__ = t.__VUE_DEVTOOLS_HOOK_REPLAY__ || []).push((i) => { + ji(i, t); + }), setTimeout(() => { + He || (t.__VUE_DEVTOOLS_HOOK_REPLAY__ = null, Vo = !0, zt = []); + }, 3e3)) : (Vo = !0, zt = []); +} +function Rl(e, t) { + dn("app:init", e, t, { + Fragment: we, + Text: hn, + Comment: xe, + Static: An + }); +} +function jl(e) { + dn("app:unmount", e); +} +const Ll = /* @__PURE__ */ rr( + "component:added" + /* COMPONENT_ADDED */ +), Li = /* @__PURE__ */ rr( + "component:updated" + /* COMPONENT_UPDATED */ +), Ul = /* @__PURE__ */ rr( + "component:removed" + /* COMPONENT_REMOVED */ +), Hl = (e) => { + He && typeof He.cleanupBuffer == "function" && // remove the component if it wasn't buffered + !He.cleanupBuffer(e) && Ul(e); +}; +function rr(e) { + return (t) => { + dn( + e, + t.appContext.app, + t.uid, + t.parent ? t.parent.uid : void 0, + t + ); + }; +} +const kl = /* @__PURE__ */ Ui( + "perf:start" + /* PERFORMANCE_START */ +), Bl = /* @__PURE__ */ Ui( + "perf:end" + /* PERFORMANCE_END */ +); +function Ui(e) { + return (t, n, o) => { + dn(e, t.appContext.app, t.uid, t, n, o); + }; +} +function Kl(e, t, n) { + dn( + "component:emit", + e.appContext.app, + e, + t, + n + ); +} +function Wl(e, t, ...n) { + if (e.isUnmounted) + return; + const o = e.vnode.props || X; + if (p.NODE_ENV !== "production") { + const { + emitsOptions: h, + propsOptions: [a] + } = e; + if (h) + if (!(t in h)) + (!a || !(ht(t) in a)) && w( + `Component emitted event "${t}" but it is neither declared in the emits option nor as an "${ht(t)}" prop.` + ); + else { + const g = h[t]; + P(g) && (g(...n) || w( + `Invalid event arguments: event validation failed for event "${t}".` + )); + } + } + let r = n; + const i = t.startsWith("update:"), s = i && t.slice(7); + if (s && s in o) { + const h = `${s === "modelValue" ? "model" : s}Modifiers`, { number: a, trim: g } = o[h] || X; + g && (r = n.map((y) => oe(y) ? y.trim() : y)), a && (r = n.map(vo)); + } + if (p.NODE_ENV !== "production" && Kl(e, t, r), p.NODE_ENV !== "production") { + const h = t.toLowerCase(); + h !== t && o[ht(h)] && w( + `Event "${h}" is emitted in component ${oo( + e, + e.type + )} but the handler is registered for "${t}". Note that HTML attributes are case-insensitive and you cannot use v-on to listen to camelCase events when using in-DOM templates. You should probably use "${Je( + t + )}" instead of "${t}".` + ); + } + let l, u = o[l = ht(t)] || // also try camelCase event handler (#2249) + o[l = ht(Rt(t))]; + !u && i && (u = o[l = ht(Je(t))]), u && Me( + u, + e, + 6, + r + ); + const f = o[l + "Once"]; + if (f) { + if (!e.emitted) + e.emitted = {}; + else if (e.emitted[l]) + return; + e.emitted[l] = !0, Me( + f, + e, + 6, + r + ); + } +} +function Hi(e, t, n = !1) { + const o = t.emitsCache, r = o.get(e); + if (r !== void 0) + return r; + const i = e.emits; + let s = {}, l = !1; + if (!P(e)) { + const u = (f) => { + const h = Hi(f, t, !0); + h && (l = !0, ne(s, h)); + }; + !n && t.mixins.length && t.mixins.forEach(u), e.extends && u(e.extends), e.mixins && e.mixins.forEach(u); + } + return !i && !l ? (Y(e) && o.set(e, null), null) : (F(i) ? i.forEach((u) => s[u] = null) : ne(s, i), Y(e) && o.set(e, s), s); +} +function Zn(e, t) { + return !e || !un(t) ? !1 : (t = t.slice(2).replace(/Once$/, ""), B(e, t[0].toLowerCase() + t.slice(1)) || B(e, Je(t)) || B(e, t)); +} +let _e = null, ki = null; +function Ln(e) { + const t = _e; + return _e = e, ki = e && e.type.__scopeId || null, t; +} +function ql(e, t = _e, n) { + if (!t || e._n) + return e; + const o = (...r) => { + o._d && Lr(-1); + const i = Ln(t); + let s; + try { + s = e(...r); + } finally { + Ln(i), o._d && Lr(1); + } + return p.NODE_ENV !== "production" && Li(t), s; + }; + return o._n = !0, o._c = !0, o._d = !0, o; +} +let So = !1; +function Un() { + So = !0; +} +function po(e) { + const { + type: t, + vnode: n, + proxy: o, + withProxy: r, + props: i, + propsOptions: [s], + slots: l, + attrs: u, + emit: f, + render: h, + renderCache: a, + data: g, + setupState: y, + ctx: x, + inheritAttrs: S + } = e; + let $, U; + const G = Ln(e); + p.NODE_ENV !== "production" && (So = !1); + try { + if (n.shapeFlag & 4) { + const k = r || o, Q = p.NODE_ENV !== "production" && y.__isScriptSetup ? new Proxy(k, { + get(A, q, re) { + return w( + `Property '${String( + q + )}' was accessed via 'this'. Avoid using 'this' in templates.` + ), Reflect.get(A, q, re); + } + }) : k; + $ = Pe( + h.call( + Q, + k, + a, + i, + y, + g, + x + ) + ), U = u; + } else { + const k = t; + p.NODE_ENV !== "production" && u === i && Un(), $ = Pe( + k.length > 1 ? k( + i, + p.NODE_ENV !== "production" ? { + get attrs() { + return Un(), u; + }, + slots: l, + emit: f + } : { attrs: u, slots: l, emit: f } + ) : k( + i, + null + /* we know it doesn't need it */ + ) + ), U = t.props ? u : Gl(u); + } + } catch (k) { + en.length = 0, an(k, e, 1), $ = Ne(xe); + } + let H = $, K; + if (p.NODE_ENV !== "production" && $.patchFlag > 0 && $.patchFlag & 2048 && ([H, K] = Bi($)), U && S !== !1) { + const k = Object.keys(U), { shapeFlag: Q } = H; + if (k.length) { + if (Q & 7) + s && k.some(Mn) && (U = zl( + U, + s + )), H = ut(H, U); + else if (p.NODE_ENV !== "production" && !So && H.type !== xe) { + const A = Object.keys(u), q = [], re = []; + for (let j = 0, Z = A.length; j < Z; j++) { + const ee = A[j]; + un(ee) ? Mn(ee) || q.push(ee[2].toLowerCase() + ee.slice(3)) : re.push(ee); + } + re.length && w( + `Extraneous non-props attributes (${re.join(", ")}) were passed to component but could not be automatically inherited because component renders fragment or text root nodes.` + ), q.length && w( + `Extraneous non-emits event listeners (${q.join(", ")}) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. If the listener is intended to be a component custom event listener only, declare it using the "emits" option.` + ); + } + } + } + return n.dirs && (p.NODE_ENV !== "production" && !Sr(H) && w( + "Runtime directive used on component with non-element root node. The directives will not function as intended." + ), H = ut(H), H.dirs = H.dirs ? H.dirs.concat(n.dirs) : n.dirs), n.transition && (p.NODE_ENV !== "production" && !Sr(H) && w( + "Component inside renders non-element root node that cannot be animated." + ), H.transition = n.transition), p.NODE_ENV !== "production" && K ? K(H) : $ = H, Ln(G), $; +} +const Bi = (e) => { + const t = e.children, n = e.dynamicChildren, o = ir(t, !1); + if (o) { + if (p.NODE_ENV !== "production" && o.patchFlag > 0 && o.patchFlag & 2048) + return Bi(o); + } else + return [e, void 0]; + const r = t.indexOf(o), i = n ? n.indexOf(o) : -1, s = (l) => { + t[r] = l, n && (i > -1 ? n[i] = l : l.patchFlag > 0 && (e.dynamicChildren = [...n, l])); + }; + return [Pe(o), s]; +}; +function ir(e, t = !0) { + let n; + for (let o = 0; o < e.length; o++) { + const r = e[o]; + if (ar(r)) { + if (r.type !== xe || r.children === "v-if") { + if (n) + return; + if (n = r, p.NODE_ENV !== "production" && t && n.patchFlag > 0 && n.patchFlag & 2048) + return ir(n.children); + } + } else + return; + } + return n; +} +const Gl = (e) => { + let t; + for (const n in e) + (n === "class" || n === "style" || un(n)) && ((t || (t = {}))[n] = e[n]); + return t; +}, zl = (e, t) => { + const n = {}; + for (const o in e) + (!Mn(o) || !(o.slice(9) in t)) && (n[o] = e[o]); + return n; +}, Sr = (e) => e.shapeFlag & 7 || e.type === xe; +function Jl(e, t, n) { + const { props: o, children: r, component: i } = e, { props: s, children: l, patchFlag: u } = t, f = i.emitsOptions; + if (p.NODE_ENV !== "production" && (r || l) && Nt || t.dirs || t.transition) + return !0; + if (n && u >= 0) { + if (u & 1024) + return !0; + if (u & 16) + return o ? Cr(o, s, f) : !!s; + if (u & 8) { + const h = t.dynamicProps; + for (let a = 0; a < h.length; a++) { + const g = h[a]; + if (s[g] !== o[g] && !Zn(f, g)) + return !0; + } + } + } else + return (r || l) && (!l || !l.$stable) ? !0 : o === s ? !1 : o ? s ? Cr(o, s, f) : !0 : !!s; + return !1; +} +function Cr(e, t, n) { + const o = Object.keys(t); + if (o.length !== Object.keys(e).length) + return !0; + for (let r = 0; r < o.length; r++) { + const i = o[r]; + if (t[i] !== e[i] && !Zn(n, i)) + return !0; + } + return !1; +} +function Yl({ vnode: e, parent: t }, n) { + for (; t; ) { + const o = t.subTree; + if (o.suspense && o.suspense.activeBranch === e && (o.el = e.el), o === e) + (e = t.vnode).el = n, t = t.parent; + else + break; + } +} +const Xl = Symbol.for("v-ndc"), Zl = (e) => e.__isSuspense; +function Ql(e, t) { + t && t.pendingBranch ? F(e) ? t.effects.push(...e) : t.effects.push(e) : Pi(e); +} +const ec = Symbol.for("v-scx"), tc = () => { + { + const e = $n(ec); + return e || p.NODE_ENV !== "production" && w( + "Server rendering context not provided. Make sure to only call useSSRContext() conditionally in the server build." + ), e; + } +}, On = {}; +function Te(e, t, n) { + return p.NODE_ENV !== "production" && !P(t) && w( + "`watch(fn, options?)` signature has been moved to a separate API. Use `watchEffect(fn, options?)` instead. `watch` now only supports `watch(source, cb, options?) signature." + ), Ki(e, t, n); +} +function Ki(e, t, { + immediate: n, + deep: o, + flush: r, + once: i, + onTrack: s, + onTrigger: l +} = X) { + if (t && i) { + const A = t; + t = (...q) => { + A(...q), Q(); + }; + } + p.NODE_ENV !== "production" && o !== void 0 && typeof o == "number" && w( + 'watch() "deep" option with number value will be used as watch depth in future versions. Please use a boolean instead to avoid potential breakage.' + ), p.NODE_ENV !== "production" && !t && (n !== void 0 && w( + 'watch() "immediate" option is only respected when using the watch(source, callback, options?) signature.' + ), o !== void 0 && w( + 'watch() "deep" option is only respected when using the watch(source, callback, options?) signature.' + ), i !== void 0 && w( + 'watch() "once" option is only respected when using the watch(source, callback, options?) signature.' + )); + const u = (A) => { + w( + "Invalid watch source: ", + A, + "A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types." + ); + }, f = fe, h = (A) => o === !0 ? A : ( + // for deep: false, only traverse root-level properties + mt(A, o === !1 ? 1 : void 0) + ); + let a, g = !1, y = !1; + if (ie(e) ? (a = () => e.value, g = bt(e)) : yt(e) ? (a = () => h(e), g = !0) : F(e) ? (y = !0, g = e.some((A) => yt(A) || bt(A)), a = () => e.map((A) => { + if (ie(A)) + return A.value; + if (yt(A)) + return h(A); + if (P(A)) + return ze(A, f, 2); + p.NODE_ENV !== "production" && u(A); + })) : P(e) ? t ? a = () => ze(e, f, 2) : a = () => (x && x(), Me( + e, + f, + 3, + [S] + )) : (a = le, p.NODE_ENV !== "production" && u(e)), t && o) { + const A = a; + a = () => mt(A()); + } + let x, S = (A) => { + x = K.onStop = () => { + ze(A, f, 4), x = K.onStop = void 0; + }; + }, $; + if (to) + if (S = le, t ? n && Me(t, f, 3, [ + a(), + y ? [] : void 0, + S + ]) : a(), r === "sync") { + const A = tc(); + $ = A.__watcherHandles || (A.__watcherHandles = []); + } else + return le; + let U = y ? new Array(e.length).fill(On) : On; + const G = () => { + if (!(!K.active || !K.dirty)) + if (t) { + const A = K.run(); + (o || g || (y ? A.some((q, re) => lt(q, U[re])) : lt(A, U))) && (x && x(), Me(t, f, 3, [ + A, + // pass undefined as the old value when it's changed for the first time + U === On ? void 0 : y && U[0] === On ? [] : U, + S + ]), U = A); + } else + K.run(); + }; + G.allowRecurse = !!t; + let H; + r === "sync" ? H = G : r === "post" ? H = () => ve(G, f && f.suspense) : (G.pre = !0, f && (G.id = f.uid), H = () => Xn(G)); + const K = new Go(a, le, H), k = qo(), Q = () => { + K.stop(), k && Uo(k.effects, K); + }; + return p.NODE_ENV !== "production" && (K.onTrack = s, K.onTrigger = l), t ? n ? G() : U = K.run() : r === "post" ? ve( + K.run.bind(K), + f && f.suspense + ) : K.run(), $ && $.push(Q), Q; +} +function nc(e, t, n) { + const o = this.proxy, r = oe(e) ? e.includes(".") ? Wi(o, e) : () => o[e] : e.bind(o, o); + let i; + P(t) ? i = t : (i = t.handler, n = t); + const s = mn(this), l = Ki(r, i.bind(o), n); + return s(), l; +} +function Wi(e, t) { + const n = t.split("."); + return () => { + let o = e; + for (let r = 0; r < n.length && o; r++) + o = o[n[r]]; + return o; + }; +} +function mt(e, t, n = 0, o) { + if (!Y(e) || e.__v_skip) + return e; + if (t && t > 0) { + if (n >= t) + return e; + n++; + } + if (o = o || /* @__PURE__ */ new Set(), o.has(e)) + return e; + if (o.add(e), ie(e)) + mt(e.value, t, n, o); + else if (F(e)) + for (let r = 0; r < e.length; r++) + mt(e[r], t, n, o); + else if (ci(e) || gt(e)) + e.forEach((r) => { + mt(r, t, n, o); + }); + else if (fi(e)) + for (const r in e) + mt(e[r], t, n, o); + return e; +} +function qi(e) { + Cs(e) && w("Do not use built-in directive ids as custom directive id: " + e); +} +function Gi(e, t) { + if (_e === null) + return p.NODE_ENV !== "production" && w("withDirectives can only be used inside render functions."), e; + const n = no(_e) || _e.proxy, o = e.dirs || (e.dirs = []); + for (let r = 0; r < t.length; r++) { + let [i, s, l, u = X] = t[r]; + i && (P(i) && (i = { + mounted: i, + updated: i + }), i.deep && mt(s), o.push({ + dir: i, + instance: n, + value: s, + oldValue: void 0, + arg: l, + modifiers: u + })); + } + return e; +} +function dt(e, t, n, o) { + const r = e.dirs, i = t && t.dirs; + for (let s = 0; s < r.length; s++) { + const l = r[s]; + i && (l.oldValue = i[s].value); + let u = l.dir[o]; + u && (ft(), Me(u, n, 8, [ + e.el, + l, + e, + t + ]), at()); + } +} +/*! #__NO_SIDE_EFFECTS__ */ +// @__NO_SIDE_EFFECTS__ +function Ht(e, t) { + return P(e) ? ( + // #8326: extend call and options.name access are considered side-effects + // by Rollup, so we have to wrap it in a pure-annotated IIFE. + ne({ name: e.name }, t, { setup: e }) + ) : e; +} +const Tn = (e) => !!e.type.__asyncLoader, sr = (e) => e.type.__isKeepAlive; +function oc(e, t) { + zi(e, "a", t); +} +function rc(e, t) { + zi(e, "da", t); +} +function zi(e, t, n = fe) { + const o = e.__wdc || (e.__wdc = () => { + let r = n; + for (; r; ) { + if (r.isDeactivated) + return; + r = r.parent; + } + return e(); + }); + if (Qn(t, o, n), n) { + let r = n.parent; + for (; r && r.parent; ) + sr(r.parent.vnode) && ic(o, t, n, r), r = r.parent; + } +} +function ic(e, t, n, o) { + const r = Qn( + t, + e, + o, + !0 + /* prepend */ + ); + pn(() => { + Uo(o[t], r); + }, n); +} +function Qn(e, t, n = fe, o = !1) { + if (n) { + const r = n[e] || (n[e] = []), i = t.__weh || (t.__weh = (...s) => { + if (n.isUnmounted) + return; + ft(); + const l = mn(n), u = Me(t, n, e, s); + return l(), at(), u; + }); + return o ? r.unshift(i) : r.push(i), i; + } else if (p.NODE_ENV !== "production") { + const r = ht(er[e].replace(/ hook$/, "")); + w( + `${r} is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup(). If you are using async setup(), make sure to register lifecycle hooks before the first await statement.` + ); + } +} +const Ze = (e) => (t, n = fe) => ( + // post-create lifecycle registrations are noops during SSR (except for serverPrefetch) + (!to || e === "sp") && Qn(e, (...o) => t(...o), n) +), sc = Ze("bm"), kt = Ze("m"), lc = Ze("bu"), cc = Ze("u"), uc = Ze("bum"), pn = Ze("um"), fc = Ze("sp"), ac = Ze( + "rtg" +), dc = Ze( + "rtc" +); +function pc(e, t = fe) { + Qn("ec", e, t); +} +function lr(e, t, n, o) { + let r; + const i = n && n[o]; + if (F(e) || oe(e)) { + r = new Array(e.length); + for (let s = 0, l = e.length; s < l; s++) + r[s] = t(e[s], s, void 0, i && i[s]); + } else if (typeof e == "number") { + p.NODE_ENV !== "production" && !Number.isInteger(e) && w(`The v-for range expect an integer value but got ${e}.`), r = new Array(e); + for (let s = 0; s < e; s++) + r[s] = t(s + 1, s, void 0, i && i[s]); + } else if (Y(e)) + if (e[Symbol.iterator]) + r = Array.from( + e, + (s, l) => t(s, l, void 0, i && i[l]) + ); + else { + const s = Object.keys(e); + r = new Array(s.length); + for (let l = 0, u = s.length; l < u; l++) { + const f = s[l]; + r[l] = t(e[f], f, l, i && i[l]); + } + } + else + r = []; + return n && (n[o] = r), r; +} +const Co = (e) => e ? fs(e) ? no(e) || e.proxy : Co(e.parent) : null, Ot = ( + // Move PURE marker to new line to workaround compiler discarding it + // due to type annotation + /* @__PURE__ */ ne(/* @__PURE__ */ Object.create(null), { + $: (e) => e, + $el: (e) => e.vnode.el, + $data: (e) => e.data, + $props: (e) => p.NODE_ENV !== "production" ? Pt(e.props) : e.props, + $attrs: (e) => p.NODE_ENV !== "production" ? Pt(e.attrs) : e.attrs, + $slots: (e) => p.NODE_ENV !== "production" ? Pt(e.slots) : e.slots, + $refs: (e) => p.NODE_ENV !== "production" ? Pt(e.refs) : e.refs, + $parent: (e) => Co(e.parent), + $root: (e) => Co(e.root), + $emit: (e) => e.emit, + $options: (e) => ur(e), + $forceUpdate: (e) => e.f || (e.f = () => { + e.effect.dirty = !0, Xn(e.update); + }), + $nextTick: (e) => e.n || (e.n = nr.bind(e.proxy)), + $watch: (e) => nc.bind(e) + }) +), cr = (e) => e === "_" || e === "$", ho = (e, t) => e !== X && !e.__isScriptSetup && B(e, t), Ji = { + get({ _: e }, t) { + const { ctx: n, setupState: o, data: r, props: i, accessCache: s, type: l, appContext: u } = e; + if (p.NODE_ENV !== "production" && t === "__isVue") + return !0; + let f; + if (t[0] !== "$") { + const y = s[t]; + if (y !== void 0) + switch (y) { + case 1: + return o[t]; + case 2: + return r[t]; + case 4: + return n[t]; + case 3: + return i[t]; + } + else { + if (ho(o, t)) + return s[t] = 1, o[t]; + if (r !== X && B(r, t)) + return s[t] = 2, r[t]; + if ( + // only cache other properties when instance has declared (thus stable) + // props + (f = e.propsOptions[0]) && B(f, t) + ) + return s[t] = 3, i[t]; + if (n !== X && B(n, t)) + return s[t] = 4, n[t]; + To && (s[t] = 0); + } + } + const h = Ot[t]; + let a, g; + if (h) + return t === "$attrs" ? (de(e, "get", t), p.NODE_ENV !== "production" && Un()) : p.NODE_ENV !== "production" && t === "$slots" && de(e, "get", t), h(e); + if ( + // css module (injected by vue-loader) + (a = l.__cssModules) && (a = a[t]) + ) + return a; + if (n !== X && B(n, t)) + return s[t] = 4, n[t]; + if ( + // global properties + g = u.config.globalProperties, B(g, t) + ) + return g[t]; + p.NODE_ENV !== "production" && _e && (!oe(t) || // #1091 avoid internal isRef/isVNode checks on component instance leading + // to infinite warning loop + t.indexOf("__v") !== 0) && (r !== X && cr(t[0]) && B(r, t) ? w( + `Property ${JSON.stringify( + t + )} must be accessed via $data because it starts with a reserved character ("$" or "_") and is not proxied on the render context.` + ) : e === _e && w( + `Property ${JSON.stringify(t)} was accessed during render but is not defined on instance.` + )); + }, + set({ _: e }, t, n) { + const { data: o, setupState: r, ctx: i } = e; + return ho(r, t) ? (r[t] = n, !0) : p.NODE_ENV !== "production" && r.__isScriptSetup && B(r, t) ? (w(`Cannot mutate \r\n\r\n","\r\n\r\n","\r\n\r\nconst toPaddedString = (x: number) => x.toString().padStart(2, '0');\r\n\r\nexport function formatDate(date: Date | null) {\r\n if (date == null) return '';\r\n const dateParts = [date.getFullYear(), date.getMonth() + 1, date.getDay()];\r\n const timeParts = [date.getHours(), date.getMinutes(), date.getSeconds()];\r\n return dateParts.map(toPaddedString).join('-') + ' ' + timeParts.map(toPaddedString).join(':');\r\n}","\r\n\r\n","\r\n\r\n","\r\n\r\n","export async function getBytes(stream, onChunk) {\r\n const reader = stream.getReader();\r\n let result;\r\n while (!(result = await reader.read()).done) {\r\n onChunk(result.value);\r\n }\r\n}\r\nexport function getLines(onLine) {\r\n let buffer;\r\n let position;\r\n let fieldLength;\r\n let discardTrailingNewline = false;\r\n return function onChunk(arr) {\r\n if (buffer === undefined) {\r\n buffer = arr;\r\n position = 0;\r\n fieldLength = -1;\r\n }\r\n else {\r\n buffer = concat(buffer, arr);\r\n }\r\n const bufLength = buffer.length;\r\n let lineStart = 0;\r\n while (position < bufLength) {\r\n if (discardTrailingNewline) {\r\n if (buffer[position] === 10) {\r\n lineStart = ++position;\r\n }\r\n discardTrailingNewline = false;\r\n }\r\n let lineEnd = -1;\r\n for (; position < bufLength && lineEnd === -1; ++position) {\r\n switch (buffer[position]) {\r\n case 58:\r\n if (fieldLength === -1) {\r\n fieldLength = position - lineStart;\r\n }\r\n break;\r\n case 13:\r\n discardTrailingNewline = true;\r\n case 10:\r\n lineEnd = position;\r\n break;\r\n }\r\n }\r\n if (lineEnd === -1) {\r\n break;\r\n }\r\n onLine(buffer.subarray(lineStart, lineEnd), fieldLength);\r\n lineStart = position;\r\n fieldLength = -1;\r\n }\r\n if (lineStart === bufLength) {\r\n buffer = undefined;\r\n }\r\n else if (lineStart !== 0) {\r\n buffer = buffer.subarray(lineStart);\r\n position -= lineStart;\r\n }\r\n };\r\n}\r\nexport function getMessages(onId, onRetry, onMessage) {\r\n let message = newMessage();\r\n const decoder = new TextDecoder();\r\n return function onLine(line, fieldLength) {\r\n if (line.length === 0) {\r\n onMessage === null || onMessage === void 0 ? void 0 : onMessage(message);\r\n message = newMessage();\r\n }\r\n else if (fieldLength > 0) {\r\n const field = decoder.decode(line.subarray(0, fieldLength));\r\n const valueOffset = fieldLength + (line[fieldLength + 1] === 32 ? 2 : 1);\r\n const value = decoder.decode(line.subarray(valueOffset));\r\n switch (field) {\r\n case 'data':\r\n message.data = message.data\r\n ? message.data + '\\n' + value\r\n : value;\r\n break;\r\n case 'event':\r\n message.event = value;\r\n break;\r\n case 'id':\r\n onId(message.id = value);\r\n break;\r\n case 'retry':\r\n const retry = parseInt(value, 10);\r\n if (!isNaN(retry)) {\r\n onRetry(message.retry = retry);\r\n }\r\n break;\r\n }\r\n }\r\n };\r\n}\r\nfunction concat(a, b) {\r\n const res = new Uint8Array(a.length + b.length);\r\n res.set(a);\r\n res.set(b, a.length);\r\n return res;\r\n}\r\nfunction newMessage() {\r\n return {\r\n data: '',\r\n event: '',\r\n id: '',\r\n retry: undefined,\r\n };\r\n}\r\n//# sourceMappingURL=parse.js.map","var __rest = (this && this.__rest) || function (s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n};\r\nimport { getBytes, getLines, getMessages } from './parse';\r\nexport const EventStreamContentType = 'text/event-stream';\r\nconst DefaultRetryInterval = 1000;\r\nconst LastEventId = 'last-event-id';\r\nexport function fetchEventSource(input, _a) {\r\n var { signal: inputSignal, headers: inputHeaders, onopen: inputOnOpen, onmessage, onclose, onerror, openWhenHidden, fetch: inputFetch } = _a, rest = __rest(_a, [\"signal\", \"headers\", \"onopen\", \"onmessage\", \"onclose\", \"onerror\", \"openWhenHidden\", \"fetch\"]);\r\n return new Promise((resolve, reject) => {\r\n const headers = Object.assign({}, inputHeaders);\r\n if (!headers.accept) {\r\n headers.accept = EventStreamContentType;\r\n }\r\n let curRequestController;\r\n function onVisibilityChange() {\r\n curRequestController.abort();\r\n if (!document.hidden) {\r\n create();\r\n }\r\n }\r\n if (!openWhenHidden) {\r\n document.addEventListener('visibilitychange', onVisibilityChange);\r\n }\r\n let retryInterval = DefaultRetryInterval;\r\n let retryTimer = 0;\r\n function dispose() {\r\n document.removeEventListener('visibilitychange', onVisibilityChange);\r\n window.clearTimeout(retryTimer);\r\n curRequestController.abort();\r\n }\r\n inputSignal === null || inputSignal === void 0 ? void 0 : inputSignal.addEventListener('abort', () => {\r\n dispose();\r\n resolve();\r\n });\r\n const fetch = inputFetch !== null && inputFetch !== void 0 ? inputFetch : window.fetch;\r\n const onopen = inputOnOpen !== null && inputOnOpen !== void 0 ? inputOnOpen : defaultOnOpen;\r\n async function create() {\r\n var _a;\r\n curRequestController = new AbortController();\r\n try {\r\n const response = await fetch(input, Object.assign(Object.assign({}, rest), { headers, signal: curRequestController.signal }));\r\n await onopen(response);\r\n await getBytes(response.body, getLines(getMessages(id => {\r\n if (id) {\r\n headers[LastEventId] = id;\r\n }\r\n else {\r\n delete headers[LastEventId];\r\n }\r\n }, retry => {\r\n retryInterval = retry;\r\n }, onmessage)));\r\n onclose === null || onclose === void 0 ? void 0 : onclose();\r\n dispose();\r\n resolve();\r\n }\r\n catch (err) {\r\n if (!curRequestController.signal.aborted) {\r\n try {\r\n const interval = (_a = onerror === null || onerror === void 0 ? void 0 : onerror(err)) !== null && _a !== void 0 ? _a : retryInterval;\r\n window.clearTimeout(retryTimer);\r\n retryTimer = window.setTimeout(create, interval);\r\n }\r\n catch (innerErr) {\r\n dispose();\r\n reject(innerErr);\r\n }\r\n }\r\n }\r\n }\r\n create();\r\n });\r\n}\r\nfunction defaultOnOpen(response) {\r\n const contentType = response.headers.get('content-type');\r\n if (!(contentType === null || contentType === void 0 ? void 0 : contentType.startsWith(EventStreamContentType))) {\r\n throw new Error(`Expected content-type to be ${EventStreamContentType}, Actual: ${contentType}`);\r\n }\r\n}\r\n//# sourceMappingURL=fetch.js.map","\r\nimport { EventSourceMessage, fetchEventSource } from \"@microsoft/fetch-event-source\";\r\n\r\ninterface IUseFetchEventSourceOptions {\r\n authToken?: string;\r\n baseUrl?: string;\r\n}\r\n\r\nconst currentOptions: IUseFetchEventSourceOptions = { baseUrl: '' };\r\n\r\nconst isIsoDateString = (dateString: string): boolean => {\r\n return /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}/.test(dateString);\r\n}\r\n\r\nconst isoDateReviver = (_: any, value: any): any => {\r\n if (typeof (value) != 'string') return value;\r\n if (!isIsoDateString(value)) return value;\r\n return new Date(value);\r\n}\r\n\r\nexport function useFetchEventSource() {\r\n\r\n function configureFetchEventSource(options: IUseFetchEventSourceOptions) {\r\n Object.assign(currentOptions, { ...currentOptions, ...options });\r\n }\r\n\r\n function listen(path: string, signal: AbortSignal, onMessage: (message: T) => void, onError: (err: any) => void) {\r\n const url = `${currentOptions.baseUrl}${path}`;\r\n\r\n fetchEventSource(url, {\r\n signal: signal,\r\n headers: { 'Authorization': `Bearer ${currentOptions.authToken}` },\r\n onmessage: (message: EventSourceMessage) => {\r\n onMessage(JSON.parse(message.data, isoDateReviver));\r\n },\r\n onerror: onError\r\n });\r\n }\r\n\r\n return {\r\n configureFetchEventSource,\r\n listen\r\n }\r\n}","\n\n","import { createApp } from 'vue'\nimport App from './App.vue'\n\ncreateApp(App).mount('#app')\n"],"names":["define_process_env_default","appLogEventKey","systemMessageEventKey","chatMessageEventKey","requestUserEventKey","requestSelectedUsersEventKey","storageLoginKey","logBus","useEventBus","defaultSource","idSource","useAppLogger","logInfo","message","source","log","logWarning","logError","logErrorObject","errorObject","severity","created","entry","errorRef","ref","watch","currentOptions","getFetchOptions","requestMethod","body","headers","ctx","useChatApi","configureChatApi","options","login","userName","loginRequest","dataRef","fetch","logout","userId","getUsers","sendMessage","path","method","bodyString","createFetch","data","error","defaultLogin","useStorageLogin","useSessionStorage","storageLogin","isVisible","computed","tryLogin","loginResponse","loginUser","messageText","requestSelectedUsersBus","onTextEnterKeyUp","ev","trySendMessage","request","selectedUserIds","x","toPaddedString","formatDate","date","dateParts","timeParts","messages","chatMessageBus","requestUserBus","onChatMessage","newMessage","onMounted","onUnmounted","users","systemMessageBus","onRequestUser","onRequestSelectedUsers","onSystemMessage","userFromMessage","user","userLogout","loadUsersWhenLoggedIn","appLogBus","logEntries","addLogEntry","getBytes","stream","onChunk","reader","result","getLines","onLine","buffer","position","fieldLength","discardTrailingNewline","arr","concat","bufLength","lineStart","lineEnd","getMessages","onId","onRetry","onMessage","decoder","line","field","valueOffset","value","retry","a","b","res","__rest","s","e","t","p","i","EventStreamContentType","DefaultRetryInterval","LastEventId","fetchEventSource","input","_a","inputSignal","inputHeaders","inputOnOpen","onmessage","onclose","onerror","openWhenHidden","inputFetch","rest","resolve","reject","curRequestController","onVisibilityChange","create","retryInterval","retryTimer","dispose","onopen","defaultOnOpen","response","id","err","interval","innerErr","contentType","isIsoDateString","dateString","isoDateReviver","_","useFetchEventSource","configureFetchEventSource","listen","signal","onError","url","sseAbortController","chatMessageEventBus","systemMessageEventBus","configureWithLogin","createApp","App"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAACA,KAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAD,IAACA,KAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAD,IAACA,IAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAD,IAACA,KAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;A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","x_google_ignoreList":[0,1,2,3,4,15,16]} \ No newline at end of file diff --git a/src/web1-sse-chat-app/.gitignore b/src/web1-sse-chat-app/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/src/web1-sse-chat-app/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/src/web1-sse-chat-app/.vscode/extensions.json b/src/web1-sse-chat-app/.vscode/extensions.json new file mode 100644 index 0000000..a7cea0b --- /dev/null +++ b/src/web1-sse-chat-app/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["Vue.volar"] +} diff --git a/src/web1-sse-chat-app/README.md b/src/web1-sse-chat-app/README.md new file mode 100644 index 0000000..0bfecb0 --- /dev/null +++ b/src/web1-sse-chat-app/README.md @@ -0,0 +1,9 @@ +# Vue 3 + TypeScript + Vite + +This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 ` + + + \ No newline at end of file diff --git a/src/web1-sse-chat-app/package-lock.json b/src/web1-sse-chat-app/package-lock.json new file mode 100644 index 0000000..42c11d9 --- /dev/null +++ b/src/web1-sse-chat-app/package-lock.json @@ -0,0 +1,1213 @@ +{ + "name": "web1-sse-chat-app", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "web1-sse-chat-app", + "version": "0.0.1", + "dependencies": { + "@microsoft/fetch-event-source": "^2.0.1", + "@vueuse/core": "^10.9.0", + "vue": "^3.4.21" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.0.4", + "typescript": "^5.2.2", + "vite": "^5.2.0", + "vue-tsc": "^2.0.6" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@microsoft/fetch-event-source": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz", + "integrity": "sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA==" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", + "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz", + "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", + "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz", + "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz", + "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", + "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz", + "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz", + "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz", + "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz", + "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz", + "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz", + "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", + "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", + "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz", + "integrity": "sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==", + "dev": true, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/language-core": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.1.5.tgz", + "integrity": "sha512-u1OHmVkCFsJqNdaM2GKuMhE67TxcEnOqJNF+VtYv2Ji8DnrUaF4FAFSNxY+MRGICl+873CsSJVKas9TQtW14LA==", + "dev": true, + "dependencies": { + "@volar/source-map": "2.1.5" + } + }, + "node_modules/@volar/source-map": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.1.5.tgz", + "integrity": "sha512-GIkAM6fHgDcTXcdH4i10fAiAZzO0HLIer8/pt3oZ9A0n7n4R5d1b2F8Xxzh/pgmgNoL+SrHX3MFxs35CKgfmtA==", + "dev": true, + "dependencies": { + "muggle-string": "^0.4.0" + } + }, + "node_modules/@volar/typescript": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.1.5.tgz", + "integrity": "sha512-zo9a3NrNMSkufIvHuExDGTfYv+zO7C5p2wg8fyP7vcqF/Qo0ztjb0ZfOgq/A85EO/MBc1Kj2Iu7PaOBtP++NMw==", + "dev": true, + "dependencies": { + "@volar/language-core": "2.1.5", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.21.tgz", + "integrity": "sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==", + "dependencies": { + "@babel/parser": "^7.23.9", + "@vue/shared": "3.4.21", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.0.2" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.21.tgz", + "integrity": "sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==", + "dependencies": { + "@vue/compiler-core": "3.4.21", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.21.tgz", + "integrity": "sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==", + "dependencies": { + "@babel/parser": "^7.23.9", + "@vue/compiler-core": "3.4.21", + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-ssr": "3.4.21", + "@vue/shared": "3.4.21", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.7", + "postcss": "^8.4.35", + "source-map-js": "^1.0.2" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.21.tgz", + "integrity": "sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==", + "dependencies": { + "@vue/compiler-dom": "3.4.21", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@vue/language-core": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.7.tgz", + "integrity": "sha512-Vh1yZX3XmYjn9yYLkjU8DN6L0ceBtEcapqiyclHne8guG84IaTzqtvizZB1Yfxm3h6m7EIvjerLO5fvOZO6IIQ==", + "dev": true, + "dependencies": { + "@volar/language-core": "~2.1.3", + "@vue/compiler-dom": "^3.4.0", + "@vue/shared": "^3.4.0", + "computeds": "^0.0.1", + "minimatch": "^9.0.3", + "path-browserify": "^1.0.1", + "vue-template-compiler": "^2.7.14" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/reactivity": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.21.tgz", + "integrity": "sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==", + "dependencies": { + "@vue/shared": "3.4.21" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.21.tgz", + "integrity": "sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==", + "dependencies": { + "@vue/reactivity": "3.4.21", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.21.tgz", + "integrity": "sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==", + "dependencies": { + "@vue/runtime-core": "3.4.21", + "@vue/shared": "3.4.21", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.21.tgz", + "integrity": "sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==", + "dependencies": { + "@vue/compiler-ssr": "3.4.21", + "@vue/shared": "3.4.21" + }, + "peerDependencies": { + "vue": "3.4.21" + } + }, + "node_modules/@vue/shared": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.21.tgz", + "integrity": "sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==" + }, + "node_modules/@vueuse/core": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.9.0.tgz", + "integrity": "sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==", + "dependencies": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "10.9.0", + "@vueuse/shared": "10.9.0", + "vue-demi": ">=0.14.7" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/core/node_modules/vue-demi": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", + "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.9.0.tgz", + "integrity": "sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA==", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.9.0.tgz", + "integrity": "sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==", + "dependencies": { + "vue-demi": ">=0.14.7" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared/node_modules/vue-demi": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", + "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/computeds": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", + "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", + "dev": true + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/magic-string": { + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", + "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.13.0", + "@rollup/rollup-android-arm64": "4.13.0", + "@rollup/rollup-darwin-arm64": "4.13.0", + "@rollup/rollup-darwin-x64": "4.13.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", + "@rollup/rollup-linux-arm64-gnu": "4.13.0", + "@rollup/rollup-linux-arm64-musl": "4.13.0", + "@rollup/rollup-linux-riscv64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-musl": "4.13.0", + "@rollup/rollup-win32-arm64-msvc": "4.13.0", + "@rollup/rollup-win32-ia32-msvc": "4.13.0", + "@rollup/rollup-win32-x64-msvc": "4.13.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/typescript": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", + "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", + "devOptional": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.6.tgz", + "integrity": "sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==", + "dev": true, + "dependencies": { + "esbuild": "^0.20.1", + "postcss": "^8.4.36", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.21.tgz", + "integrity": "sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==", + "dependencies": { + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-sfc": "3.4.21", + "@vue/runtime-dom": "3.4.21", + "@vue/server-renderer": "3.4.21", + "@vue/shared": "3.4.21" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-template-compiler": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", + "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", + "dev": true, + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/vue-tsc": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.7.tgz", + "integrity": "sha512-LYa0nInkfcDBB7y8jQ9FQ4riJTRNTdh98zK/hzt4gEpBZQmf30dPhP+odzCa+cedGz6B/guvJEd0BavZaRptjg==", + "dev": true, + "dependencies": { + "@volar/typescript": "~2.1.3", + "@vue/language-core": "2.0.7", + "semver": "^7.5.4" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } +} diff --git a/src/web1-sse-chat-app/package.json b/src/web1-sse-chat-app/package.json new file mode 100644 index 0000000..dd31ec0 --- /dev/null +++ b/src/web1-sse-chat-app/package.json @@ -0,0 +1,22 @@ +{ + "name": "web1-sse-chat-app", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "vue": "^3.4.21", + "@microsoft/fetch-event-source": "^2.0.1", + "@vueuse/core": "^10.9.0" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.0.4", + "typescript": "^5.2.2", + "vite": "^5.2.0", + "vue-tsc": "^2.0.6" + } +} \ No newline at end of file diff --git a/src/web1-sse-chat-app/src/App.vue b/src/web1-sse-chat-app/src/App.vue new file mode 100644 index 0000000..f3d0b6d --- /dev/null +++ b/src/web1-sse-chat-app/src/App.vue @@ -0,0 +1,76 @@ + + + \ No newline at end of file diff --git a/src/web1-sse-chat-app/src/assets/main.css b/src/web1-sse-chat-app/src/assets/main.css new file mode 100644 index 0000000..c984824 --- /dev/null +++ b/src/web1-sse-chat-app/src/assets/main.css @@ -0,0 +1,146 @@ +html, +body { + height: 100%; + margin: 0px; + padding: 0px; +} + +#app, +div.main { + width: 100%; + height: 100%; +} + +div.overlay { + position: absolute; + top: 0px; + left: 0px; + width: 100%; + height: 100%; + z-index: 998; + background-color: rgba(1, 1, 1, .8) +} + +form.login { + position: relative; + margin: 20% auto; + padding: 20px; + width: 300px; + background-color: #DDD; + border-radius: 5px; + text-align: right; +} + +form.login>input { + margin: 4px; +} + +div.users { + height: 100%; + width: 240px; + background-color: #444; + float: right; +} + +div.users>div { + color: #aaa; + margin: 2px; + padding: 4px; + cursor: pointer; +} + +div.users>div.is-selected { + background-color: #777; +} + +div.messages { + width: calc(100% - 240px); + height: calc(100% - 90px); + float: left; + display: flex; + flex-direction: column-reverse; +} + +div.messages>div { + margin: 4px; + border: solid #AAA 1px; + border-radius: 5px; + background-color: #b6dcf2; + padding: 6px; + margin-right: 200px; +} + +div.messages>div.from-self { + margin-right: 4px; + margin-left: 200px; +} + +div.message-form { + padding: 5px; + height: 80px; + width: calc(100% - 250px); + float: left; +} + +div.message-form * { + height: 100%; +} + +div.message-form>form>div:nth-child(2) { + float: right; + width: 80px; +} + +div.message-form>form>div:nth-child(1) { + float: left; + width: calc(100% - 80px); +} + +div.messages>div>div.header { + color: #777; + font-size: 0.7em; +} + +div.app-log { + position: absolute; + padding: 10px; + width: 500px; + height: 80px; + top: 0px; + left: calc(50% - 250px); + background-color: #DDD; + overflow-y: scroll; + scrollbar-width: thin; + scrollbar-color: #999 #DDD; + display: flex; + flex-direction: column-reverse; + font-size: 10px; + z-index: 998; +} + +div.app-log>div.error { + color: #B33; +} + +div.app-log>div.warning { + color: #BB3; +} + +div.app-log>div.info { + color: #33B; +} + +div.app-log>div>span { + display: inline-block; + width: 120px; + margin: 2px; + overflow: hidden; +} + +div.app-log>div>span:nth-child(2) { + width: 80px; +} + +div.app-log>div>span:nth-child(3) { + width: 268px; +} \ No newline at end of file diff --git a/src/web1-sse-chat-app/src/assets/pure-3.0.0.css b/src/web1-sse-chat-app/src/assets/pure-3.0.0.css new file mode 100644 index 0000000..acdc431 --- /dev/null +++ b/src/web1-sse-chat-app/src/assets/pure-3.0.0.css @@ -0,0 +1,11 @@ +/*! +Pure v3.0.0 +Copyright 2013 Yahoo! +Licensed under the BSD License. +https://github.com/pure-css/pure/blob/master/LICENSE +*/ +/*! +normalize.css v | MIT License | https://necolas.github.io/normalize.css/ +Copyright (c) Nicolas Gallagher and Jonathan Neal +*/ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}html{font-family:sans-serif}.hidden,[hidden]{display:none!important}.pure-img{max-width:100%;height:auto;display:block}.pure-g{display:flex;flex-flow:row wrap;align-content:flex-start}.pure-u{display:inline-block;vertical-align:top}.pure-u-1,.pure-u-1-1,.pure-u-1-12,.pure-u-1-2,.pure-u-1-24,.pure-u-1-3,.pure-u-1-4,.pure-u-1-5,.pure-u-1-6,.pure-u-1-8,.pure-u-10-24,.pure-u-11-12,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-2-24,.pure-u-2-3,.pure-u-2-5,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24,.pure-u-3-24,.pure-u-3-4,.pure-u-3-5,.pure-u-3-8,.pure-u-4-24,.pure-u-4-5,.pure-u-5-12,.pure-u-5-24,.pure-u-5-5,.pure-u-5-6,.pure-u-5-8,.pure-u-6-24,.pure-u-7-12,.pure-u-7-24,.pure-u-7-8,.pure-u-8-24,.pure-u-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1-24{width:4.1667%}.pure-u-1-12,.pure-u-2-24{width:8.3333%}.pure-u-1-8,.pure-u-3-24{width:12.5%}.pure-u-1-6,.pure-u-4-24{width:16.6667%}.pure-u-1-5{width:20%}.pure-u-5-24{width:20.8333%}.pure-u-1-4,.pure-u-6-24{width:25%}.pure-u-7-24{width:29.1667%}.pure-u-1-3,.pure-u-8-24{width:33.3333%}.pure-u-3-8,.pure-u-9-24{width:37.5%}.pure-u-2-5{width:40%}.pure-u-10-24,.pure-u-5-12{width:41.6667%}.pure-u-11-24{width:45.8333%}.pure-u-1-2,.pure-u-12-24{width:50%}.pure-u-13-24{width:54.1667%}.pure-u-14-24,.pure-u-7-12{width:58.3333%}.pure-u-3-5{width:60%}.pure-u-15-24,.pure-u-5-8{width:62.5%}.pure-u-16-24,.pure-u-2-3{width:66.6667%}.pure-u-17-24{width:70.8333%}.pure-u-18-24,.pure-u-3-4{width:75%}.pure-u-19-24{width:79.1667%}.pure-u-4-5{width:80%}.pure-u-20-24,.pure-u-5-6{width:83.3333%}.pure-u-21-24,.pure-u-7-8{width:87.5%}.pure-u-11-12,.pure-u-22-24{width:91.6667%}.pure-u-23-24{width:95.8333%}.pure-u-1,.pure-u-1-1,.pure-u-24-24,.pure-u-5-5{width:100%}.pure-button{display:inline-block;line-height:normal;white-space:nowrap;vertical-align:middle;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;user-select:none;box-sizing:border-box}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-group{letter-spacing:-.31em;text-rendering:optimizespeed}.opera-only :-o-prefocus,.pure-button-group{word-spacing:-0.43em}.pure-button-group .pure-button{letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-button{font-family:inherit;font-size:100%;padding:.5em 1em;color:rgba(0,0,0,.8);border:none transparent;background-color:#e6e6e6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:focus,.pure-button:hover{background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset;border-color:#000}.pure-button-disabled,.pure-button-disabled:active,.pure-button-disabled:focus,.pure-button-disabled:hover,.pure-button[disabled]{border:none;background-image:none;opacity:.4;cursor:not-allowed;box-shadow:none;pointer-events:none}.pure-button-hidden{display:none}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-button-group .pure-button{margin:0;border-radius:0;border-right:1px solid rgba(0,0,0,.2)}.pure-button-group .pure-button:first-child{border-top-left-radius:2px;border-bottom-left-radius:2px}.pure-button-group .pure-button:last-child{border-top-right-radius:2px;border-bottom-right-radius:2px;border-right:none}.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;vertical-align:middle;box-sizing:border-box}.pure-form input:not([type]){padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;box-sizing:border-box}.pure-form input[type=color]{padding:.2em .5em}.pure-form input[type=color]:focus,.pure-form input[type=date]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=email]:focus,.pure-form input[type=month]:focus,.pure-form input[type=number]:focus,.pure-form input[type=password]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=text]:focus,.pure-form input[type=time]:focus,.pure-form input[type=url]:focus,.pure-form input[type=week]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;border-color:#129fea}.pure-form input:not([type]):focus{outline:0;border-color:#129fea}.pure-form input[type=checkbox]:focus,.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus{outline:thin solid #129FEA;outline:1px auto #129FEA}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=color][disabled],.pure-form input[type=date][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=email][disabled],.pure-form input[type=month][disabled],.pure-form input[type=number][disabled],.pure-form input[type=password][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=text][disabled],.pure-form input[type=time][disabled],.pure-form input[type=url][disabled],.pure-form input[type=week][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input:not([type])[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background-color:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form select:focus:invalid,.pure-form textarea:focus:invalid{color:#b94a48;border-color:#e9322d}.pure-form input[type=checkbox]:focus:invalid:focus,.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{height:2.25em;border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=color],.pure-form-stacked input[type=date],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=email],.pure-form-stacked input[type=file],.pure-form-stacked input[type=month],.pure-form-stacked input[type=number],.pure-form-stacked input[type=password],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=text],.pure-form-stacked input[type=time],.pure-form-stacked input[type=url],.pure-form-stacked input[type=week],.pure-form-stacked label,.pure-form-stacked select,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-stacked input:not([type]){display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned select,.pure-form-aligned textarea,.pure-form-message-inline{display:inline-block;vertical-align:middle}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 11em}.pure-form .pure-input-rounded,.pure-form input.pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input,.pure-form .pure-group textarea{display:block;padding:10px;margin:0 0 -1px;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus,.pure-form .pure-group textarea:focus{z-index:3}.pure-form .pure-group input:first-child,.pure-form .pure-group textarea:first-child{top:1px;border-radius:4px 4px 0 0;margin:0}.pure-form .pure-group input:first-child:last-child,.pure-form .pure-group textarea:first-child:last-child{top:1px;border-radius:4px;margin:0}.pure-form .pure-group input:last-child,.pure-form .pure-group textarea:last-child{top:-2px;border-radius:0 0 4px 4px;margin:0}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-3-4{width:75%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=color],.pure-group input[type=date],.pure-group input[type=datetime-local],.pure-group input[type=datetime],.pure-group input[type=email],.pure-group input[type=month],.pure-group input[type=number],.pure-group input[type=password],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=text],.pure-group input[type=time],.pure-group input[type=url],.pure-group input[type=week]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0 0}.pure-form-message,.pure-form-message-inline{display:block;font-size:.75em;padding:.2em 0 .8em}}.pure-menu{box-sizing:border-box}.pure-menu-fixed{position:fixed;left:0;top:0;z-index:3}.pure-menu-item,.pure-menu-list{position:relative}.pure-menu-list{list-style:none;margin:0;padding:0}.pure-menu-item{padding:0;margin:0;height:100%}.pure-menu-heading,.pure-menu-link{display:block;text-decoration:none;white-space:nowrap}.pure-menu-horizontal{width:100%;white-space:nowrap}.pure-menu-horizontal .pure-menu-list{display:inline-block}.pure-menu-horizontal .pure-menu-heading,.pure-menu-horizontal .pure-menu-item,.pure-menu-horizontal .pure-menu-separator{display:inline-block;vertical-align:middle}.pure-menu-item .pure-menu-item{display:block}.pure-menu-children{display:none;position:absolute;left:100%;top:0;margin:0;padding:0;z-index:3}.pure-menu-horizontal .pure-menu-children{left:0;top:auto;width:inherit}.pure-menu-active>.pure-menu-children,.pure-menu-allow-hover:hover>.pure-menu-children{display:block;position:absolute}.pure-menu-has-children>.pure-menu-link:after{padding-left:.5em;content:"\25B8";font-size:small}.pure-menu-horizontal .pure-menu-has-children>.pure-menu-link:after{content:"\25BE"}.pure-menu-scrollable{overflow-y:scroll;overflow-x:hidden}.pure-menu-scrollable .pure-menu-list{display:block}.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list{display:inline-block}.pure-menu-horizontal.pure-menu-scrollable{white-space:nowrap;overflow-y:hidden;overflow-x:auto;padding:.5em 0}.pure-menu-horizontal .pure-menu-children .pure-menu-separator,.pure-menu-separator{background-color:#ccc;height:1px;margin:.3em 0}.pure-menu-horizontal .pure-menu-separator{width:1px;height:1.3em;margin:0 .3em}.pure-menu-horizontal .pure-menu-children .pure-menu-separator{display:block;width:auto}.pure-menu-heading{text-transform:uppercase;color:#565d64}.pure-menu-link{color:#777}.pure-menu-children{background-color:#fff}.pure-menu-heading,.pure-menu-link{padding:.5em 1em}.pure-menu-disabled{opacity:.5}.pure-menu-disabled .pure-menu-link:hover{background-color:transparent;cursor:default}.pure-menu-active>.pure-menu-link,.pure-menu-link:focus,.pure-menu-link:hover{background-color:#eee}.pure-menu-selected>.pure-menu-link,.pure-menu-selected>.pure-menu-link:visited{color:#000}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.5em 1em}.pure-table thead{background-color:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child>td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child>td{border-bottom-width:0} \ No newline at end of file diff --git a/src/web1-sse-chat-app/src/components/AppLogComponent.vue b/src/web1-sse-chat-app/src/components/AppLogComponent.vue new file mode 100644 index 0000000..7e7f3c3 --- /dev/null +++ b/src/web1-sse-chat-app/src/components/AppLogComponent.vue @@ -0,0 +1,33 @@ + + + \ No newline at end of file diff --git a/src/web1-sse-chat-app/src/components/LoginComponent.vue b/src/web1-sse-chat-app/src/components/LoginComponent.vue new file mode 100644 index 0000000..dc93620 --- /dev/null +++ b/src/web1-sse-chat-app/src/components/LoginComponent.vue @@ -0,0 +1,35 @@ + + + \ No newline at end of file diff --git a/src/web1-sse-chat-app/src/components/MessageFormComponent.vue b/src/web1-sse-chat-app/src/components/MessageFormComponent.vue new file mode 100644 index 0000000..e7a15ab --- /dev/null +++ b/src/web1-sse-chat-app/src/components/MessageFormComponent.vue @@ -0,0 +1,54 @@ + + + \ No newline at end of file diff --git a/src/web1-sse-chat-app/src/components/MessagesComponent.vue b/src/web1-sse-chat-app/src/components/MessagesComponent.vue new file mode 100644 index 0000000..a4bd4e7 --- /dev/null +++ b/src/web1-sse-chat-app/src/components/MessagesComponent.vue @@ -0,0 +1,38 @@ + + + \ No newline at end of file diff --git a/src/web1-sse-chat-app/src/components/UsersComponent.vue b/src/web1-sse-chat-app/src/components/UsersComponent.vue new file mode 100644 index 0000000..a8f8c0b --- /dev/null +++ b/src/web1-sse-chat-app/src/components/UsersComponent.vue @@ -0,0 +1,81 @@ + + + \ No newline at end of file diff --git a/src/web1-sse-chat-app/src/composables/useAppLogger.ts b/src/web1-sse-chat-app/src/composables/useAppLogger.ts new file mode 100644 index 0000000..320844b --- /dev/null +++ b/src/web1-sse-chat-app/src/composables/useAppLogger.ts @@ -0,0 +1,49 @@ +import { appLogEventKey } from './../symbols'; +import { useEventBus } from '@vueuse/core'; +import { LogSeverity, ILogEntry } from '../models'; +import { Ref, ref, watch } from 'vue'; + +const logBus = useEventBus(appLogEventKey); +const defaultSource = 'app'; +let idSource = 1; + +export function useAppLogger() { + + function logInfo(message: string, source = defaultSource) { + log(message, source, 'info'); + } + + function logWarning(message: string, source = defaultSource) { + log(message, source, 'warning'); + } + + function logError(message: string, source = defaultSource) { + log(message, source, 'error'); + } + + function logErrorObject(errorObject: any, source = defaultSource) { + if (errorObject ?? null == null) return; + const message: string = typeof (errorObject) == 'string' ? errorObject : errorObject?.message ?? 'Unspecified error'; + log(message, source, 'error'); + } + + function log(message: string, source = defaultSource, severity: LogSeverity = 'info', created = new Date()) { + const entry: ILogEntry = { id: ++idSource, message, source, severity, created }; + logBus.emit(entry); + } + + const errorRef: Ref = ref(); + + watch(errorRef, () => { + logErrorObject(errorRef.value); + }); + + return { + logInfo, + logWarning, + logError, + logErrorObject, + log, + errorRef + }; +} \ No newline at end of file diff --git a/src/web1-sse-chat-app/src/composables/useChatApi.ts b/src/web1-sse-chat-app/src/composables/useChatApi.ts new file mode 100644 index 0000000..ccdf3ec --- /dev/null +++ b/src/web1-sse-chat-app/src/composables/useChatApi.ts @@ -0,0 +1,76 @@ + +import { createFetch, CreateFetchOptions } from '@vueuse/core'; +import { IChatApiOptions, ILoginRequest, ILoginResponse, IChatUser, IChatMessageOut } from '../models'; +import { ref, Ref } from 'vue'; + + +enum RequestMethod { + GET = 'GET', + POST = 'POST', + PUT = 'PUT', + DELETE = 'DELETE' +}; + +const currentOptions: IChatApiOptions = { + baseUrl: '', +}; + +function getFetchOptions(requestMethod: RequestMethod = RequestMethod.GET, body?: BodyInit): CreateFetchOptions { + const headers: any = { 'Content-Type': 'application/json' }; + if (currentOptions.authToken != undefined) headers['Authorization'] = `Bearer ${currentOptions.authToken}`; + return { + baseUrl: currentOptions.baseUrl, + options: { + onFetchError(ctx) { + return { error: ctx.data?.detail }; + }, + }, + fetchOptions: { + headers: headers, + method: requestMethod, + body: body + } + } +} + +export function useChatApi() { + + function configureChatApi(options: IChatApiOptions) { + Object.assign(currentOptions, { ...currentOptions, ...options }); + } + + async function login(userName: string, errorRef: Ref): Promise { + const loginRequest: ILoginRequest = { name: userName }; + const dataRef: Ref = ref(null); + await fetch('/users/login', RequestMethod.POST, loginRequest, dataRef, errorRef); + return dataRef.value; + } + + async function logout(userId: number, errorRef: Ref): Promise { + await fetch(`/users/${userId}`, RequestMethod.DELETE, null, null, errorRef); + } + + async function getUsers(dataRef: Ref, errorRef: Ref) { + await fetch('/users', RequestMethod.GET, undefined, dataRef, errorRef); + } + + async function sendMessage(message: IChatMessageOut, errorRef: Ref): Promise { + await fetch('/messages', RequestMethod.POST, message, null, errorRef); + } + + async function fetch(path: string, method: RequestMethod, body?: any, dataRef: Ref | null = null, errorRef: Ref | null = null) { + const bodyString: string | undefined = body == undefined ? undefined : JSON.stringify(body); + const fetch = createFetch(getFetchOptions(method, bodyString)); + const { data, error } = await fetch(path).json(); + if (dataRef != null) dataRef.value = data.value; + if (errorRef != null) errorRef.value = error.value; + } + + return { + configureChatApi, + login, + logout, + getUsers, + sendMessage + }; +} \ No newline at end of file diff --git a/src/web1-sse-chat-app/src/composables/useFetchEventSource.ts b/src/web1-sse-chat-app/src/composables/useFetchEventSource.ts new file mode 100644 index 0000000..b768904 --- /dev/null +++ b/src/web1-sse-chat-app/src/composables/useFetchEventSource.ts @@ -0,0 +1,44 @@ + +import { EventSourceMessage, fetchEventSource } from "@microsoft/fetch-event-source"; + +interface IUseFetchEventSourceOptions { + authToken?: string; + baseUrl?: string; +} + +const currentOptions: IUseFetchEventSourceOptions = { baseUrl: '' }; + +const isIsoDateString = (dateString: string): boolean => { + return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(dateString); +} + +const isoDateReviver = (_: any, value: any): any => { + if (typeof (value) != 'string') return value; + if (!isIsoDateString(value)) return value; + return new Date(value); +} + +export function useFetchEventSource() { + + function configureFetchEventSource(options: IUseFetchEventSourceOptions) { + Object.assign(currentOptions, { ...currentOptions, ...options }); + } + + function listen(path: string, signal: AbortSignal, onMessage: (message: T) => void, onError: (err: any) => void) { + const url = `${currentOptions.baseUrl}${path}`; + + fetchEventSource(url, { + signal: signal, + headers: { 'Authorization': `Bearer ${currentOptions.authToken}` }, + onmessage: (message: EventSourceMessage) => { + onMessage(JSON.parse(message.data, isoDateReviver)); + }, + onerror: onError + }); + } + + return { + configureFetchEventSource, + listen + } +} \ No newline at end of file diff --git a/src/web1-sse-chat-app/src/composables/useStorageLogin.ts b/src/web1-sse-chat-app/src/composables/useStorageLogin.ts new file mode 100644 index 0000000..fa2ac7e --- /dev/null +++ b/src/web1-sse-chat-app/src/composables/useStorageLogin.ts @@ -0,0 +1,9 @@ +import { ILoginUser } from '../models'; +import { storageLoginKey } from '../symbols'; +import { RemovableRef, useSessionStorage } from '@vueuse/core'; + +export const defaultLogin: ILoginUser = { id: 0, name: '', authToken: '' }; + +export function useStorageLogin(): RemovableRef { + return useSessionStorage(storageLoginKey, defaultLogin); +} \ No newline at end of file diff --git a/src/web1-sse-chat-app/src/formatters.ts b/src/web1-sse-chat-app/src/formatters.ts new file mode 100644 index 0000000..a6e5381 --- /dev/null +++ b/src/web1-sse-chat-app/src/formatters.ts @@ -0,0 +1,10 @@ + + +const toPaddedString = (x: number) => x.toString().padStart(2, '0'); + +export function formatDate(date: Date | null) { + if (date == null) return ''; + const dateParts = [date.getFullYear(), date.getMonth() + 1, date.getDay()]; + const timeParts = [date.getHours(), date.getMinutes(), date.getSeconds()]; + return dateParts.map(toPaddedString).join('-') + ' ' + timeParts.map(toPaddedString).join(':'); +} \ No newline at end of file diff --git a/src/web1-sse-chat-app/src/main.ts b/src/web1-sse-chat-app/src/main.ts new file mode 100644 index 0000000..01433bc --- /dev/null +++ b/src/web1-sse-chat-app/src/main.ts @@ -0,0 +1,4 @@ +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/src/web1-sse-chat-app/src/models.ts b/src/web1-sse-chat-app/src/models.ts new file mode 100644 index 0000000..2515091 --- /dev/null +++ b/src/web1-sse-chat-app/src/models.ts @@ -0,0 +1,68 @@ + + +export interface ILoginRequest { + name: string; +} + +export interface ILoginResponse { + userId: number; + token: string; +} + +export interface IChatApiOptions { + baseUrl?: string; + authToken?: string; +} + +export interface IUserBase { + id: number; + name: string; +} + +export interface IChatUser extends IUserBase { + isSelected: boolean; +} + +export interface ILoginUser extends IUserBase { + authToken: string; +} + +export interface IChatMessageOut { + fromUserId: number; + toUserIds: number[]; + text: string; +} + +export interface IChatMessageIn extends IChatMessageOut { + id: number; + created: Date; +} + +export interface IChatMessage extends IChatMessageIn { + fromUserName: string; + fromSelf: boolean; +} + +export interface ISystemMessage { + messageType: string; + data: any; +} + +export type LogSeverity = 'info' | 'warning' | 'error'; + +export interface ILogEntry { + id: number; + created: Date; + source?: string; + severity: string; + message: string; +} + +export interface IRequestUser { + userId: number; + user?: IChatUser; +} + +export interface IRequestSelectedUsers { + users: IChatUser[]; +} \ No newline at end of file diff --git a/src/web1-sse-chat-app/src/symbols.ts b/src/web1-sse-chat-app/src/symbols.ts new file mode 100644 index 0000000..c9a4e15 --- /dev/null +++ b/src/web1-sse-chat-app/src/symbols.ts @@ -0,0 +1,11 @@ +import type { EventBusKey } from '@vueuse/core'; +import { ISystemMessage, IChatMessageIn, IRequestUser, ILogEntry, IRequestSelectedUsers } from './models'; + + +export const appLogEventKey: EventBusKey = Symbol('log-event'); +export const systemMessageEventKey: EventBusKey = Symbol('system-message-event'); +export const chatMessageEventKey: EventBusKey = Symbol('chat-message-event'); +export const requestUserEventKey: EventBusKey = Symbol('request-user-event'); +export const requestSelectedUsersEventKey: EventBusKey = Symbol('request-selected-users-event'); + +export const storageLoginKey = 'user-login'; \ No newline at end of file diff --git a/src/web1-sse-chat-app/src/vite-env.d.ts b/src/web1-sse-chat-app/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/src/web1-sse-chat-app/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/src/web1-sse-chat-app/tsconfig.json b/src/web1-sse-chat-app/tsconfig.json new file mode 100644 index 0000000..9e03e60 --- /dev/null +++ b/src/web1-sse-chat-app/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/src/web1-sse-chat-app/tsconfig.node.json b/src/web1-sse-chat-app/tsconfig.node.json new file mode 100644 index 0000000..97ede7e --- /dev/null +++ b/src/web1-sse-chat-app/tsconfig.node.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "strict": true + }, + "include": ["vite.config.ts"] +} diff --git a/src/web1-sse-chat-app/vite.config.ts b/src/web1-sse-chat-app/vite.config.ts new file mode 100644 index 0000000..1865ec6 --- /dev/null +++ b/src/web1-sse-chat-app/vite.config.ts @@ -0,0 +1,21 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue()], + define: { + 'process.env': {} + }, + build: { + lib: { + entry: './index.html', + name: 'web1-sse-chat-app', + fileName: 'web1-sse-chat-app', + formats: ['es'] + }, + outDir: './../Web1.Sse.ChatApi/wwwroot', + sourcemap: true, + target: 'esnext' + } +})