From 8ae2f323af0d3074babb4ae4b2ee4c312476326a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 23:57:41 +0000 Subject: [PATCH 1/4] Initial plan From 47052078cb71af2216d0701a006b9997573d652d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 00:08:24 +0000 Subject: [PATCH 2/4] Merge master into copilot/sub-pr-567 - resolve conflicts for CourseMentor model Co-authored-by: DedSec256 <26364714+DedSec256@users.noreply.github.com> --- .github/workflows/build.yml | 28 + .github/workflows/deploy.yml | 2 + .gitignore | 1 + Directory.Build.props | 2 +- .../ApplicationProfile.cs | 18 +- .../Controllers/AccountController.cs | 26 +- .../Controllers/AggregationController.cs | 57 +- .../Controllers/CourseGroupsController.cs | 161 +- .../Controllers/CoursesController.cs | 495 +- .../Controllers/ExpertsController.cs | 205 +- .../Controllers/FilesController.cs | 129 +- .../Controllers/HomeworksController.cs | 101 +- .../Controllers/NotificationsController.cs | 99 +- .../Controllers/SolutionsController.cs | 894 +- .../Controllers/StatisticsController.cs | 239 +- .../Controllers/SystemController.cs | 107 +- .../Controllers/TasksController.cs | 154 +- .../HwProj.APIGateway.API/Dockerfile | 5 +- .../ForbiddenExceptionFilter.cs | 18 +- .../Filters/CourseMentorOnlyAttribute.cs | 106 +- .../Filters/FilesCountLimiter.cs | 27 + .../Filters/FilesPrivacyFilter.cs | 71 + .../HwProj.APIGateway.API.csproj | 21 +- .../Models/CoursePreviewView.cs | 35 +- .../Models/Solutions/PostSolutionModel.cs | 55 + .../Models/Solutions/SolutionPreviewView.cs | 40 +- .../Models/Solutions/UserTaskSolutions.cs | 105 +- .../AdvancedCourseStatisticsViewModel.cs | 19 +- .../Statistics/StatisticsCourseMatesModel.cs | 17 +- .../Statistics/StatisticsLecturersModel.cs | 13 +- .../Models/SystemInfo.cs | 11 +- .../Models/Tasks/TaskDeadlineView.cs | 17 +- .../Models/UserDataDto.cs | 13 +- .../HwProj.APIGateway.API/Program.cs | 32 +- .../HwProj.APIGateway.API/Startup.cs | 168 +- .../HwProj.APIGateway.API/appsettings.json | 5 +- .../ApplicationProfile.cs | 1 + .../Controllers/AccountController.cs | 17 +- .../HwProj.AuthService.API/Dockerfile | 10 +- .../Extensions/MappingExtensions.cs | 23 + .../HwProj.AuthService.API.csproj | 23 +- .../Models/ExpertData.cs | 3 +- .../Models/IdentityContext.cs | 3 +- .../HwProj.AuthService.API/Models/User.cs | 25 + .../Repositories/ExpertsRepository.cs | 4 +- .../Repositories/IExpertsRepository.cs | 4 +- .../HwProj.AuthService.API/RoleInitializer.cs | 14 +- .../Services/AccountService.cs | 11 +- .../Services/AuthTokenService.cs | 2 +- .../Services/ExpertsService.cs | 6 +- .../Services/IAccountService.cs | 1 + .../Services/IAuthTokenService.cs | 2 +- .../Services/IUserManager.cs | 2 +- .../Services/ProxyUserManager.cs | 2 +- .../HwProj.AuthService.API/Startup.cs | 73 +- .../HwProj.AuthService.API/appsettings.json | 2 +- .../AuthServiceClient.cs | 8 +- .../IAuthServiceClient.cs | 2 +- .../AuthServiceTests.cs | 11 +- .../HwProj.Common.Net8/ConnectionString.cs | 16 + .../HwProj.Common.Net8.csproj | 14 + .../HwProj.Common.Net8/StartupExtensions.cs | 38 + .../ViewModels/RegisterExpertViewModel.cs | 4 +- .../Attributes/CorrectFileTypeAttribute.cs | 59 + .../Attributes/FileValidationAttribute.cs | 22 + .../Attributes/MaxFileSizeAttribute.cs | 21 +- .../CourseUnitType/CourseUnitType.cs | 9 + .../DTO/CourseFilesTransferDTO.cs | 11 + .../ContentService/DTO/FileInfoDTO.cs | 9 +- .../ContentService/DTO/FileLinkDTO.cs | 11 + .../ContentService/DTO/ProcessFilesDTO.cs | 17 + .../ContentService/DTO/ScopeDTO.cs | 9 + .../ContentService/DTO/ScopeMappingPairDTO.cs | 8 + .../ViewModels/CourseViewModels.cs | 15 +- .../ViewModels/CriterionViewModel.cs | 17 + .../ViewModels/HomeworkTaskViewModels.cs | 11 +- .../ViewModels/HomeworkViewModels.cs | 2 +- .../ViewModels/QuestionModels.cs | 7 + .../HwProj.Models/HwProj.Models.csproj | 7 +- HwProj.Common/HwProj.Models/Roles/Roles.cs | 7 +- .../SolutionsService/GetSolutionModel.cs | 2 + .../SolutionsService/PostSolutionModel.cs | 14 - .../SolutionsService/Solution.cs | 3 +- .../CrudRepository.cs | 67 + .../HwProj.Repositories.Net8.csproj | 11 + .../ICrudRepository.cs | 21 + .../HwProj.Repositories.Net8/IEntity.cs | 9 + .../HwProj.Repositories/CrudRepository.cs | 2 +- .../HwProj.Repositories.csproj | 2 +- .../HwProj.Repositories/ReadOnlyRepository.cs | 2 +- .../HwProj.Utils/Auth/AuthExtensions.cs | 26 - .../Configuration/StartupExtensions.cs | 76 - .../ExternalStorageConfiguration.cs | 10 + .../LocalStorageConfiguration.cs | 6 + .../Controllers/FilesController.cs | 124 +- .../Controllers/SystemController.cs | 11 + .../Extensions/AmazonS3Extensions.cs | 20 - .../Extensions/ConfigurationExtensions.cs | 96 +- .../Extensions/MappingExtensions.cs | 31 + .../Extensions/WebApplicationExtensions.cs | 52 +- .../HwProj.ContentService.API.csproj | 14 +- ...0511214729_AddFileRecordsTable.Designer.cs | 67 + .../20250511214729_AddFileRecordsTable.cs | 45 + ...4851_AddFileToCourseUnitsTable.Designer.cs | 101 + ...0250511214851_AddFileToCourseUnitsTable.cs | 51 + .../Migrations/ContentContextModelSnapshot.cs | 98 + .../Models/DTO/FileTransferDTO.cs | 13 + .../Models/DTO/UploadFileTaskDto.cs | 9 + .../Models/DTO/UploadFileToS3Dto.cs | 8 + .../Models/Database/ContentContext.cs | 22 + .../Models/Database/FileRecord.cs | 16 + .../Models/Database/FileToCourseUnit.cs | 13 + .../Models/Enums/CourseUnitType.cs | 8 + .../Models/Enums/FileStatus.cs | 10 + .../Models/Messages/DeleteFileMessage.cs | 6 + .../Models/Messages/FileDeletedMessage.cs | 5 + .../Models/Messages/IProcessFileMessage.cs | 6 + .../Models/Messages/ReDeleteFileMessage.cs | 5 + .../Models/Messages/ReUploadFileMessage.cs | 5 + .../Models/Messages/UpdateStatusMessage.cs | 9 + .../Models/Messages/UploadFileMessage.cs | 9 + .../HwProj.ContentService.API/Models/Scope.cs | 9 + .../HwProj.ContentService.API/Program.cs | 29 +- .../Repositories/FileRecordRepository.cs | 177 + .../Repositories/IFileRecordRepository.cs | 24 + .../Services/FileKeyService.cs | 62 +- .../Services/FilesInfoService.cs | 87 + .../Services/Interfaces/IFileKeyService.cs | 9 + .../Services/Interfaces/IFilesInfoService.cs | 15 + .../Services/Interfaces/ILocalFilesService.cs | 11 + .../Services/Interfaces/IMessageProducer.cs | 14 + .../Services/Interfaces/IRecoveryService.cs | 6 + .../Services/Interfaces/IS3FilesService.cs | 13 + .../Services/LocalFilesService.cs | 62 + .../Services/MessageConsumer.cs | 339 + .../Services/MessageProducer.cs | 92 + .../Services/RecoveryService.cs | 62 + .../Services/S3FilesService.cs | 193 + .../appsettings.json | 13 +- .../ContentServiceClient.cs | 135 +- .../IContentServiceClient.cs | 15 +- .../ApplicationProfile.cs | 2 +- .../Controllers/CoursesController.cs | 30 +- .../Controllers/HomeworksController.cs | 10 +- .../Controllers/TasksController.cs | 97 +- .../HwProj.CoursesService.API/Dockerfile | 2 + .../Domains/MappingExtensions.cs | 49 +- .../Domains/Validations.cs | 3 +- .../HwProj.CoursesService.API.csproj | 2 + .../20251230213439_Criteria.Designer.cs | 356 + .../Migrations/20251230213439_Criteria.cs | 44 + .../Migrations/CourseContextModelSnapshot.cs | 31 +- .../Models/Course.cs | 6 +- .../Models/CourseContext.cs | 3 +- .../Models/Criterion.cs | 21 + .../Models/HomeworkTask.cs | 5 +- .../Repositories/CoursesRepository.cs | 15 +- .../Repositories/HomeworksRepository.cs | 8 +- .../Repositories/ICoursesRepository.cs | 2 +- .../Repositories/IHomeworksRepository.cs | 2 +- .../Repositories/ITaskQuestionsRepository.cs | 8 - .../Repositories/ITasksRepository.cs | 9 +- .../Repositories/TaskQuestionsRepository.cs | 13 + .../Repositories/TasksRepository.cs | 79 +- .../Services/CourseFilterUtils.cs | 1 - .../Services/CoursesService.cs | 53 +- .../Services/HomeworksService.cs | 22 +- .../Services/ICoursesService.cs | 4 +- .../Services/IHomeworksService.cs | 8 +- .../Services/ITaskQuestionsService.cs | 16 + .../Services/ITasksService.cs | 11 +- .../Services/TaskQuestionsService.cs | 47 + .../Services/TasksService.cs | 46 +- .../HwProj.CoursesService.API/Startup.cs | 4 + .../CoursesServiceClient.cs | 70 +- .../ICoursesServiceClient.cs | 15 +- .../CoursesServiceTests.cs | 86 +- .../ConfigurationExtensions.cs | 59 + .../HwProj.EventBus.Client.csproj | 4 +- .../Implementations/EventBusRabbitMQ.cs | 8 +- .../AuthService/AdminRegisterEvent.cs | 11 + .../AuthService/InviteLecturerEvent.cs | 10 + .../AuthService/PasswordRecoveryEvent.cs | 13 + .../AuthService/RegisterEvent.cs | 22 + .../AuthService/StudentRegisterEvent.cs | 11 + .../LecturerAcceptToCourseEvent.cs | 12 + .../LecturerInvitedToCourseEvent.cs | 12 + .../LecturerRejectToCourseEvent.cs | 12 + .../CoursesService/NewCourseMateEvent.cs | 13 + .../CoursesService/NewHomeworkEvent.cs | 23 + .../CoursesService/NewHomeworkTaskEvent.cs | 25 + .../CoursesService/UpdateHomeworkEvent.cs | 20 + .../UpdateSolutionMaxRatingEvent.cs | 18 + .../UpdateTaskMaxRatingEvent.cs | 22 + .../HwProj.NotificationService.Events.csproj | 12 + .../SolutionsService/RateEvent.cs | 18 + .../SolutionsService/StudentPassTaskEvent.cs | 23 + .../AutomapperProfile.cs | 1 + .../NotificationSettingsController.cs | 1 - .../Dockerfile | 12 +- .../InviteLecturerEventHandler.cs | 5 +- .../LecturerAcceptToCourseEventHandler.cs | 4 +- .../LecturerInvitedToCourseEventHandler.cs | 3 +- .../LecturerRejectToCourseEventHandler.cs | 4 +- .../EventHandlers/NewCourseMateHandler.cs | 1 - .../EventHandlers/NewHomeworkEventHandler.cs | 4 +- .../NewHomeworkTaskEventHandler.cs | 4 +- .../PasswordRecoveryEventHandler.cs | 5 +- .../EventHandlers/RateEventHandler.cs | 4 +- .../EventHandlers/RegisterEventHandler.cs | 4 +- .../StudentPassTaskEventHandler.cs | 4 +- .../UpdateHomeworkEventHandler.cs | 4 +- .../UpdateTaskMaxRatingEventHandler.cs | 4 +- .../HwProj.NotificationsService.API.csproj | 25 +- .../Models/Notification.cs | 21 + .../Models/NotificationCategoryState.cs | 10 + .../Models/NotificationsContext.cs | 3 +- .../Repositories/INotificationsRepository.cs | 4 +- .../Repositories/NotificationsRepository.cs | 3 +- .../Services/EmailService.cs | 2 +- .../Services/IEmailService.cs | 4 +- .../Startup.cs | 38 +- .../appsettings.json | 2 +- .../HwProj.SolutionsService.API/Dockerfile | 1 + .../HwProj.SolutionsService.API.csproj | 1 + ...50909235525_SolutionIsModified.Designer.cs | 74 + .../20250909235525_SolutionIsModified.cs | 23 + .../SolutionContextModelSnapshot.cs | 2 + .../Services/SolutionsService.cs | 5 +- .../HwProj.SolutionsService.API/Startup.cs | 1 + .../SolutionsServiceTests.cs | 30 +- .../IStudentsInfo/IStudentsInfo.csproj | 4 + .../IStudentsInfo/IStudentsInformation.cs | 2 +- .../StudentsInformationTests.cs | 4 +- .../StudentsInfo/StudentsInformation.cs | 162 +- HwProj.sln | 21 + README.md | 47 +- backups_builder.sh | 86 + cleanup_old_backups.sh | 13 + docker-compose.override.yml | 69 +- docker-compose.yml | 21 +- generate-swagger-client.ps1 | 6 +- hwproj.front/.env | 2 +- hwproj.front/Dockerfile | 6 +- hwproj.front/eslint.config.js | 3 +- hwproj.front/package-lock.json | 17567 +++++++++------- hwproj.front/package.json | 14 +- hwproj.front/src/App.tsx | 5 - hwproj.front/src/api/ApiSingleton.ts | 15 +- hwproj.front/src/api/CustomFilesApi.ts | 41 +- hwproj.front/src/api/api.ts | 3462 +-- hwproj.front/src/components/Auth/Login.tsx | 69 +- .../src/components/Auth/PasswordRecovery.tsx | 7 +- hwproj.front/src/components/Auth/Register.tsx | 9 +- .../src/components/Common/HomeworkTags.tsx | 2 +- .../src/components/Common/MarkdownEditor.tsx | 62 +- .../src/components/Common/MentorsList.tsx | 18 +- .../src/components/Common/StudentTags.ts | 1 + .../Styles/MarkdownEditorCommands.ru.tsx | 226 + hwproj.front/src/components/Common/Tags.tsx | 39 +- .../src/components/Common/UserAvatar.tsx | 17 + .../src/components/Courses/AddCourseInfo.tsx | 96 +- .../src/components/Courses/Course.tsx | 267 +- .../components/Courses/CourseExperimental.tsx | 520 +- .../src/components/Courses/CourseFilter.tsx | 121 +- .../src/components/Courses/Courses.tsx | 21 +- .../src/components/Courses/CoursesList.tsx | 42 +- .../src/components/Courses/CreateCourse.tsx | 16 +- .../components/Courses/ICreateCourseState.tsx | 6 +- .../Courses/MentorWorkspaceModal.tsx | 108 +- .../components/Courses/NewCourseStudents.tsx | 13 +- .../Courses/Statistics/StudentStatsChart.tsx | 35 +- .../Courses/Statistics/StudentsRadarChart.tsx | 55 + .../src/components/Courses/StudentStats.tsx | 104 +- .../Courses/Styles/StudentStatsCell.css | 24 + hwproj.front/src/components/EditProfile.tsx | 21 +- .../src/components/Experts/InviteModal.tsx | 10 +- .../src/components/Experts/Notebook.tsx | 3 +- .../src/components/Experts/RegisterModal.tsx | 91 +- .../src/components/Files/CourseUnitType.ts | 5 + .../src/components/Files/FilePreview.tsx | 276 +- .../src/components/Files/FileStatus.ts | 8 + .../src/components/Files/FilesHandler.ts | 85 + .../src/components/Files/FilesPreviewList.tsx | 32 +- .../src/components/Files/FilesUploadWaiter.ts | 181 + .../src/components/Files/FilesUploader.tsx | 104 +- .../src/components/Files/IFileInfo.ts | 8 +- .../src/components/Files/IProcessFilesDto.ts | 9 + .../Files/filesUploaderOverrides.css | 4 + .../Homeworks/CourseHomeworkExperimental.tsx | 359 +- .../Solutions/AddOrEditSolution.tsx | 106 +- .../Solutions/StudentSolutionsPage.tsx | 118 +- .../Solutions/TaskSolutionComponent.tsx | 1088 +- .../components/Solutions/TaskSolutions.tsx | 55 +- .../Solutions/TaskSolutionsPage.tsx | 39 +- .../UnratedSolutionsAndOpenQuestions.tsx | 308 + .../Students/StudentCharacteristics.tsx | 9 +- .../Tasks/CourseTaskExperimental.tsx | 413 +- .../src/components/Tasks/StudentStatsCell.tsx | 32 +- .../src/components/Tasks/TaskDeadlines.tsx | 6 - .../src/components/Tasks/TaskQuestions.tsx | 24 +- .../src/components/Utils/ErrorsHandler.tsx | 8 +- .../src/components/Utils/FileInfoConverter.ts | 23 +- .../src/components/Utils/ProcessFilesUtils.ts | 20 + hwproj.front/src/components/Workspace.tsx | 27 +- hwproj.front/src/services/AuthService.ts | 10 +- hwproj.front/src/services/Utils.ts | 8 +- hwproj.front/vite.config.ts | 3 +- restore_from_backup.sh | 70 + send_to_yadisk.sh | 20 + 310 files changed, 22493 insertions(+), 12890 deletions(-) create mode 100644 .github/workflows/build.yml create mode 100644 HwProj.APIGateway/HwProj.APIGateway.API/Filters/FilesCountLimiter.cs create mode 100644 HwProj.APIGateway/HwProj.APIGateway.API/Filters/FilesPrivacyFilter.cs create mode 100644 HwProj.APIGateway/HwProj.APIGateway.API/Models/Solutions/PostSolutionModel.cs create mode 100644 HwProj.AuthService/HwProj.AuthService.API/Extensions/MappingExtensions.cs create mode 100644 HwProj.AuthService/HwProj.AuthService.API/Models/User.cs create mode 100644 HwProj.Common/HwProj.Common.Net8/ConnectionString.cs create mode 100644 HwProj.Common/HwProj.Common.Net8/HwProj.Common.Net8.csproj create mode 100644 HwProj.Common/HwProj.Common.Net8/StartupExtensions.cs create mode 100644 HwProj.Common/HwProj.Models/ContentService/Attributes/CorrectFileTypeAttribute.cs create mode 100644 HwProj.Common/HwProj.Models/ContentService/Attributes/FileValidationAttribute.cs create mode 100644 HwProj.Common/HwProj.Models/ContentService/CourseUnitType/CourseUnitType.cs create mode 100644 HwProj.Common/HwProj.Models/ContentService/DTO/CourseFilesTransferDTO.cs create mode 100644 HwProj.Common/HwProj.Models/ContentService/DTO/FileLinkDTO.cs create mode 100644 HwProj.Common/HwProj.Models/ContentService/DTO/ProcessFilesDTO.cs create mode 100644 HwProj.Common/HwProj.Models/ContentService/DTO/ScopeDTO.cs create mode 100644 HwProj.Common/HwProj.Models/ContentService/DTO/ScopeMappingPairDTO.cs create mode 100644 HwProj.Common/HwProj.Models/CoursesService/ViewModels/CriterionViewModel.cs create mode 100644 HwProj.Common/HwProj.Repositories.Net8/CrudRepository.cs create mode 100644 HwProj.Common/HwProj.Repositories.Net8/HwProj.Repositories.Net8.csproj create mode 100644 HwProj.Common/HwProj.Repositories.Net8/ICrudRepository.cs create mode 100644 HwProj.Common/HwProj.Repositories.Net8/IEntity.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Configuration/ExternalStorageConfiguration.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Configuration/LocalStorageConfiguration.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Controllers/SystemController.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Extensions/MappingExtensions.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Migrations/20250511214729_AddFileRecordsTable.Designer.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Migrations/20250511214729_AddFileRecordsTable.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Migrations/20250511214851_AddFileToCourseUnitsTable.Designer.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Migrations/20250511214851_AddFileToCourseUnitsTable.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Migrations/ContentContextModelSnapshot.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Models/DTO/FileTransferDTO.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Models/DTO/UploadFileTaskDto.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Models/DTO/UploadFileToS3Dto.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Models/Database/ContentContext.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Models/Database/FileRecord.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Models/Database/FileToCourseUnit.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Models/Enums/CourseUnitType.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Models/Enums/FileStatus.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Models/Messages/DeleteFileMessage.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Models/Messages/FileDeletedMessage.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Models/Messages/IProcessFileMessage.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Models/Messages/ReDeleteFileMessage.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Models/Messages/ReUploadFileMessage.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Models/Messages/UpdateStatusMessage.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Models/Messages/UploadFileMessage.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Models/Scope.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Repositories/FileRecordRepository.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Repositories/IFileRecordRepository.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Services/FilesInfoService.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IFileKeyService.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IFilesInfoService.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/ILocalFilesService.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IMessageProducer.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IRecoveryService.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IS3FilesService.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Services/LocalFilesService.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Services/MessageConsumer.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Services/MessageProducer.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Services/RecoveryService.cs create mode 100644 HwProj.ContentService/HwProj.ContentService.API/Services/S3FilesService.cs create mode 100644 HwProj.CoursesService/HwProj.CoursesService.API/Migrations/20251230213439_Criteria.Designer.cs create mode 100644 HwProj.CoursesService/HwProj.CoursesService.API/Migrations/20251230213439_Criteria.cs create mode 100644 HwProj.CoursesService/HwProj.CoursesService.API/Models/Criterion.cs create mode 100644 HwProj.CoursesService/HwProj.CoursesService.API/Repositories/TaskQuestionsRepository.cs create mode 100644 HwProj.CoursesService/HwProj.CoursesService.API/Services/ITaskQuestionsService.cs create mode 100644 HwProj.CoursesService/HwProj.CoursesService.API/Services/TaskQuestionsService.cs create mode 100644 HwProj.EventBus/HwProj.EventBus.Client/ConfigurationExtensions.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/AdminRegisterEvent.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/InviteLecturerEvent.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/PasswordRecoveryEvent.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/RegisterEvent.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/StudentRegisterEvent.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/LecturerAcceptToCourseEvent.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/LecturerInvitedToCourseEvent.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/LecturerRejectToCourseEvent.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/NewCourseMateEvent.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/NewHomeworkEvent.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/NewHomeworkTaskEvent.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/UpdateHomeworkEvent.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/UpdateSolutionMaxRatingEvent.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/UpdateTaskMaxRatingEvent.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/HwProj.NotificationService.Events.csproj create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/SolutionsService/RateEvent.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationService.Events/SolutionsService/StudentPassTaskEvent.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationsService.API/Models/Notification.cs create mode 100644 HwProj.NotificationsService/HwProj.NotificationsService.API/Models/NotificationCategoryState.cs create mode 100644 HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/20250909235525_SolutionIsModified.Designer.cs create mode 100644 HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/20250909235525_SolutionIsModified.cs create mode 100644 backups_builder.sh create mode 100644 cleanup_old_backups.sh create mode 100644 hwproj.front/src/components/Common/StudentTags.ts create mode 100644 hwproj.front/src/components/Common/Styles/MarkdownEditorCommands.ru.tsx create mode 100644 hwproj.front/src/components/Common/UserAvatar.tsx create mode 100644 hwproj.front/src/components/Courses/Statistics/StudentsRadarChart.tsx create mode 100644 hwproj.front/src/components/Courses/Styles/StudentStatsCell.css create mode 100644 hwproj.front/src/components/Files/CourseUnitType.ts create mode 100644 hwproj.front/src/components/Files/FileStatus.ts create mode 100644 hwproj.front/src/components/Files/FilesHandler.ts create mode 100644 hwproj.front/src/components/Files/FilesUploadWaiter.ts create mode 100644 hwproj.front/src/components/Files/IProcessFilesDto.ts create mode 100644 hwproj.front/src/components/Files/filesUploaderOverrides.css create mode 100644 hwproj.front/src/components/Solutions/UnratedSolutionsAndOpenQuestions.tsx create mode 100644 hwproj.front/src/components/Utils/ProcessFilesUtils.ts create mode 100644 restore_from_backup.sh create mode 100644 send_to_yadisk.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..2ea1b1972 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,28 @@ +name: Build (.NET 8) + +on: + push: + branches: [ master ] + pull_request: + +jobs: + build: + runs-on: windows-latest + env: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + DOTNET_CLI_TELEMETRY_OPTOUT: true + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET 8 + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' + cache: true + cache-dependency-path: | + **/*.csproj + **/*.sln + + - name: Build + run: dotnet build HwProj.sln -c Release diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index cd093db5a..ec90a1b8e 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -11,8 +11,10 @@ jobs: uses: appleboy/ssh-action@master with: host: ${{ secrets.SSH_HOST }} + port: ${{ secrets.SSH_PORT }} username: ${{ secrets.SSH_USER }} key: ${{ secrets.SSH_PRIVATE_KEY }} + command_timeout: 30m script: | cd /home/${{ secrets.SSH_USER }}/docker/HwProj-2.0.1 echo "${{ secrets.SUDO_PASSWORD }}" | sudo -S ./update.sh diff --git a/.gitignore b/.gitignore index f67737477..7ed326a27 100644 --- a/.gitignore +++ b/.gitignore @@ -361,3 +361,4 @@ StyleCop.Cache .env swagger-codegen hwproj.front/static_dist/ +hwproj.front/dist/ diff --git a/Directory.Build.props b/Directory.Build.props index 733e4e7e8..12f6f9719 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,4 +7,4 @@ enable - \ No newline at end of file + diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/ApplicationProfile.cs b/HwProj.APIGateway/HwProj.APIGateway.API/ApplicationProfile.cs index 1df12835c..509d438c6 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/ApplicationProfile.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/ApplicationProfile.cs @@ -1,18 +1,14 @@ using AutoMapper; -using HwProj.Models.AuthService.DTO; using HwProj.Models.AuthService.ViewModels; -using HwProj.Models.CoursesService; using HwProj.Models.CoursesService.DTO; -using HwProj.Models.CoursesService.ViewModels; -namespace HwProj.APIGateway.API +namespace HwProj.APIGateway.API; + +public class ApplicationProfile : Profile { - public class ApplicationProfile : Profile + public ApplicationProfile() { - public ApplicationProfile() - { - CreateMap(); - CreateMap(); - } + CreateMap(); + CreateMap(); } -} \ No newline at end of file +} diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/AccountController.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/AccountController.cs index ddc60b9ce..cf6c21e1f 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/AccountController.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/AccountController.cs @@ -18,20 +18,12 @@ namespace HwProj.APIGateway.API.Controllers { [Route("api/[controller]")] [ApiController] - public class AccountController : AggregationController + public class AccountController( + IAuthServiceClient authClient, + ICoursesServiceClient coursesClient, + ISolutionsServiceClient solutionsServiceClient) + : AggregationController(authClient) { - private readonly ICoursesServiceClient _coursesClient; - private readonly ISolutionsServiceClient _solutionsServiceClient; - - public AccountController( - IAuthServiceClient authClient, - ICoursesServiceClient coursesClient, - ISolutionsServiceClient solutionsServiceClient) : base(authClient) - { - _coursesClient = coursesClient; - _solutionsServiceClient = solutionsServiceClient; - } - [HttpGet("getUserData/{userId}")] [ProducesResponseType(typeof(AccountDataDto), (int)HttpStatusCode.OK)] public async Task GetUserDataById(string userId) @@ -52,7 +44,7 @@ public async Task GetUserData() if (User.IsInRole(Roles.LecturerRole)) { - var courses = await _coursesClient.GetAllUserCourses(); + var courses = await coursesClient.GetAllUserCourses(); var courseEvents = courses .Select(t => new CourseEvents { @@ -74,9 +66,9 @@ public async Task GetUserData() } var currentTime = DateTime.UtcNow; - var taskDeadlines = await _coursesClient.GetTaskDeadlines(); + var taskDeadlines = await coursesClient.GetTaskDeadlines(); var taskIds = taskDeadlines.Select(t => t.TaskId).ToArray(); - var solutions = await _solutionsServiceClient.GetLastTaskSolutions(taskIds, UserId); + var solutions = await solutionsServiceClient.GetLastTaskSolutions(taskIds, UserId); var taskDeadlinesInfo = taskDeadlines .Zip(solutions, (deadline, solution) => (deadline, solution)) .Where(t => currentTime <= t.deadline.DeadlineDate || t.solution == null) @@ -160,7 +152,7 @@ public async Task ResetPassword(ResetPasswordViewModel model) { return await AuthServiceClient.ResetPassword(model); } - + [Authorize] [HttpPost("github/url")] [ProducesResponseType(typeof(UrlDto), (int)HttpStatusCode.OK)] diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/AggregationController.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/AggregationController.cs index 2b852598c..0fc62e69b 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/AggregationController.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/AggregationController.cs @@ -5,39 +5,38 @@ using HwProj.Models.CoursesService.ViewModels; using Microsoft.AspNetCore.Mvc; -namespace HwProj.APIGateway.API.Controllers +namespace HwProj.APIGateway.API.Controllers; + +public class AggregationController : ControllerBase { - public class AggregationController : ControllerBase - { - protected readonly IAuthServiceClient AuthServiceClient; + protected readonly IAuthServiceClient AuthServiceClient; - protected AggregationController(IAuthServiceClient authServiceClient) - { - AuthServiceClient = authServiceClient; - } + protected AggregationController(IAuthServiceClient authServiceClient) + { + AuthServiceClient = authServiceClient; + } - protected string? UserId => - Request.HttpContext.User.Claims - .FirstOrDefault(claim => claim.Type.ToString() == "_id") - ?.Value; + protected string? UserId => + Request.HttpContext.User.Claims + .FirstOrDefault(claim => claim.Type.ToString() == "_id") + ?.Value; - protected async Task GetCoursePreviews(CoursePreview[] courses) + protected async Task GetCoursePreviews(CoursePreview[] courses) + { + var mentorIds = courses.SelectMany(t => t.MentorIds).Distinct().ToArray(); + var mentors = await AuthServiceClient.GetAccountsData(mentorIds); + var mentorsDict = mentors.Where(x => x != null).ToDictionary(x => x.UserId); + return courses.Select(course => new CoursePreviewView { - var mentorIds = courses.SelectMany(t => t.MentorIds).Distinct().ToArray(); - var mentors = await AuthServiceClient.GetAccountsData(mentorIds); - var mentorsDict = mentors.Where(x => x != null).ToDictionary(x => x.UserId); - return courses.Select(course => new CoursePreviewView - { - Id = course.Id, - Name = course.Name, - GroupName = course.GroupName, - IsCompleted = course.IsCompleted, - Mentors = course.MentorIds - .Select(x => mentorsDict.TryGetValue(x, out var mentor) ? mentor : null) - .Where(x => x != null) - .ToArray()!, - TaskId = course.TaskId - }).ToArray(); - } + Id = course.Id, + Name = course.Name, + GroupName = course.GroupName, + IsCompleted = course.IsCompleted, + Mentors = course.MentorIds + .Select(x => mentorsDict.TryGetValue(x, out var mentor) ? mentor : null) + .Where(x => x != null) + .ToArray()!, + TaskId = course.TaskId + }).ToArray(); } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/CourseGroupsController.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/CourseGroupsController.cs index 2ef9ea662..4d1bbd78f 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/CourseGroupsController.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/CourseGroupsController.cs @@ -7,97 +7,96 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace HwProj.APIGateway.API.Controllers +namespace HwProj.APIGateway.API.Controllers; + +[Route("api/[controller]")] +[ApiController] +public class CourseGroupsController : AggregationController { - [Route("api/[controller]")] - [ApiController] - public class CourseGroupsController : AggregationController - { - private readonly ICoursesServiceClient _coursesClient; + private readonly ICoursesServiceClient _coursesClient; - public CourseGroupsController(ICoursesServiceClient coursesClient) : base(null) - { - _coursesClient = coursesClient; - } + public CourseGroupsController(ICoursesServiceClient coursesClient) : base(null) + { + _coursesClient = coursesClient; + } - [HttpGet("{courseId}/getAll")] - [ProducesResponseType(typeof(GroupViewModel[]), (int)HttpStatusCode.OK)] - public async Task GetAllCourseGroups(long courseId) - { - var result = await _coursesClient.GetAllCourseGroups(courseId); - return result == null - ? NotFound() as IActionResult - : Ok(result); - } + [HttpGet("{courseId}/getAll")] + [ProducesResponseType(typeof(GroupViewModel[]), (int)HttpStatusCode.OK)] + public async Task GetAllCourseGroups(long courseId) + { + var result = await _coursesClient.GetAllCourseGroups(courseId); + return result == null + ? NotFound() + : Ok(result); + } - [HttpPost("{courseId}/create")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(long), (int)HttpStatusCode.OK)] - public async Task CreateCourseGroup(CreateGroupViewModel model, long courseId) - { - var result = await _coursesClient.CreateCourseGroup(model, courseId); - return Ok(result); - } + [HttpPost("{courseId}/create")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(long), (int)HttpStatusCode.OK)] + public async Task CreateCourseGroup(CreateGroupViewModel model, long courseId) + { + var result = await _coursesClient.CreateCourseGroup(model, courseId); + return Ok(result); + } - [HttpDelete("{courseId}/delete/{groupId}")] - [Authorize(Roles = Roles.LecturerRole)] - public async Task DeleteCourseGroup(long courseId, long groupId) - { - await _coursesClient.DeleteCourseGroup(courseId, groupId); - return Ok(); - } + [HttpDelete("{courseId}/delete/{groupId}")] + [Authorize(Roles = Roles.LecturerRole)] + public async Task DeleteCourseGroup(long courseId, long groupId) + { + await _coursesClient.DeleteCourseGroup(courseId, groupId); + return Ok(); + } - [HttpPost("{courseId}/update/{groupId}")] - [Authorize(Roles = Roles.LecturerRole)] - public async Task UpdateCourseGroup(UpdateGroupViewModel model, long courseId, long groupId) - { - await _coursesClient.UpdateCourseGroup(model, courseId, groupId); - return Ok(); - } + [HttpPost("{courseId}/update/{groupId}")] + [Authorize(Roles = Roles.LecturerRole)] + public async Task UpdateCourseGroup(UpdateGroupViewModel model, long courseId, long groupId) + { + await _coursesClient.UpdateCourseGroup(model, courseId, groupId); + return Ok(); + } - [HttpGet("{courseId}/get")] - [Authorize] - [ProducesResponseType(typeof(GroupViewModel), (int)HttpStatusCode.OK)] - public async Task GetCourseGroupsById(long courseId) - { - var result = await _coursesClient.GetCourseGroupsById(courseId, UserId); - return result == null - ? NotFound() as IActionResult - : Ok(result); - } + [HttpGet("{courseId}/get")] + [Authorize] + [ProducesResponseType(typeof(GroupViewModel), (int)HttpStatusCode.OK)] + public async Task GetCourseGroupsById(long courseId) + { + var result = await _coursesClient.GetCourseGroupsById(courseId, UserId); + return result == null + ? NotFound() + : Ok(result); + } - [HttpPost("{courseId}/addStudentInGroup/{groupId}")] - [Authorize(Roles = Roles.LecturerRole)] - public async Task AddStudentInGroup(long courseId, long groupId, [FromQuery] string userId) - { - await _coursesClient.AddStudentInGroup(courseId, groupId, userId); - return Ok(); - } + [HttpPost("{courseId}/addStudentInGroup/{groupId}")] + [Authorize(Roles = Roles.LecturerRole)] + public async Task AddStudentInGroup(long courseId, long groupId, [FromQuery] string userId) + { + await _coursesClient.AddStudentInGroup(courseId, groupId, userId); + return Ok(); + } - [HttpPost("{courseId}/removeStudentFromGroup/{groupId}")] - [Authorize(Roles = Roles.LecturerRole)] - public async Task RemoveStudentFromGroup(long courseId, long groupId, [FromQuery] string userId) - { - await _coursesClient.RemoveStudentFromGroup(courseId, groupId, userId); - return Ok(); - } + [HttpPost("{courseId}/removeStudentFromGroup/{groupId}")] + [Authorize(Roles = Roles.LecturerRole)] + public async Task RemoveStudentFromGroup(long courseId, long groupId, [FromQuery] string userId) + { + await _coursesClient.RemoveStudentFromGroup(courseId, groupId, userId); + return Ok(); + } - [HttpGet("get/{groupId}")] - [ProducesResponseType(typeof(GroupViewModel), (int)HttpStatusCode.OK)] - public async Task GetGroup(long groupId) - { - var result = (await _coursesClient.GetGroupsById(groupId)).FirstOrDefault(); - return result == null - ? NotFound() as IActionResult - : Ok(result); - } + [HttpGet("get/{groupId}")] + [ProducesResponseType(typeof(GroupViewModel), (int)HttpStatusCode.OK)] + public async Task GetGroup(long groupId) + { + var result = (await _coursesClient.GetGroupsById(groupId)).FirstOrDefault(); + return result == null + ? NotFound() + : Ok(result); + } - [HttpGet("getTasks/{groupId}")] - [ProducesResponseType(typeof(long[]), (int)HttpStatusCode.OK)] - public async Task GetGroupTasks(long groupId) - { - var result = await _coursesClient.GetGroupTasks(groupId); - return Ok(result); - } + [HttpGet("getTasks/{groupId}")] + [ProducesResponseType(typeof(long[]), (int)HttpStatusCode.OK)] + public async Task GetGroupTasks(long groupId) + { + var result = await _coursesClient.GetGroupTasks(groupId); + return Ok(result); } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/CoursesController.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/CoursesController.cs index 8caac02bc..7ad6bf87a 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/CoursesController.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/CoursesController.cs @@ -11,292 +11,305 @@ using HwProj.Models.CoursesService.DTO; using HwProj.Models.CoursesService.ViewModels; using HwProj.Models.Roles; +using IStudentsInfo; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Options; -using IStudentsInfo; -namespace HwProj.APIGateway.API.Controllers +namespace HwProj.APIGateway.API.Controllers; + +[Route("api/[controller]")] +[ApiController] +public class CoursesController : AggregationController { - [Route("api/[controller]")] - [ApiController] - public class CoursesController : AggregationController + private readonly ICoursesServiceClient _coursesClient; + private readonly IMapper _mapper; + private readonly IStudentsInformationProvider _studentsInfo; + + public CoursesController( + ICoursesServiceClient coursesClient, + IAuthServiceClient authServiceClient, + IMapper mapper, + IStudentsInformationProvider studentsInfo) : base(authServiceClient) { - private readonly ICoursesServiceClient _coursesClient; - private readonly IMapper _mapper; - private readonly IStudentsInformationProvider _studentsInfo; - - public CoursesController( - ICoursesServiceClient coursesClient, - IAuthServiceClient authServiceClient, - IMapper mapper, - IStudentsInformationProvider studentsInfo) : base(authServiceClient) - { - _coursesClient = coursesClient; - _mapper = mapper; - _studentsInfo = studentsInfo; - } + _coursesClient = coursesClient; + _mapper = mapper; + _studentsInfo = studentsInfo; + } - [HttpGet] - [Authorize] - public async Task GetAllCourses() - { - var courses = await _coursesClient.GetAllCourses(); - var result = await GetCoursePreviews(courses); - return result; - } + [HttpGet] + [Authorize] + public async Task GetAllCourses() + { + var courses = await _coursesClient.GetAllCourses(); + var result = await GetCoursePreviews(courses); + return result; + } + + [HttpGet("getAllData/{courseId}")] + [ProducesResponseType(typeof(CourseAllData), (int)HttpStatusCode.OK)] + public async Task GetAllCourseData(long courseId) + { + var courseResult = await _coursesClient.GetCourseDataRaw(courseId); + if (!courseResult.Succeeded) + return BadRequest(courseResult.Errors[0]); - [HttpGet("getAllData/{courseId}")] - [ProducesResponseType(typeof(CourseViewModel), (int)HttpStatusCode.OK)] - public async Task GetAllCourseData(long courseId) + var assignedStudents = await _coursesClient.GetMentorsToAssignedStudents(courseId); + var result = new CourseAllData { - var courseResult = await _coursesClient.GetAllCourseData(courseId); - if (!courseResult.Succeeded) - return BadRequest(courseResult.Errors[0]); + Course = await ToCourseViewModel(courseResult.Value), + AssignedStudents = assignedStudents + }; + return Ok(result); + } - var result = await ToCourseViewModel(courseResult.Value); - return Ok(result); - } + [HttpGet("{courseId}")] + [ProducesResponseType(typeof(CourseViewModel), (int)HttpStatusCode.OK)] + public async Task GetCourseData(long courseId) + { + var course = await _coursesClient.GetCourseView(courseId); + if (course == null) return NotFound(); - [HttpGet("{courseId}")] - [ProducesResponseType(typeof(CourseViewModel), (int)HttpStatusCode.OK)] - public async Task GetCourseData(long courseId) - { - var course = await _coursesClient.GetCourseById(courseId); - if (course == null) return NotFound(); + var result = await ToCourseViewModel(course); + return Ok(result); + } - var result = await ToCourseViewModel(course); - return Ok(result); - } + [HttpDelete("{courseId}")] + [Authorize(Roles = Roles.LecturerRole)] + public async Task DeleteCourse(long courseId) + { + await _coursesClient.DeleteCourse(courseId); + return Ok(); + } - [HttpDelete("{courseId}")] - [Authorize(Roles = Roles.LecturerRole)] - public async Task DeleteCourse(long courseId) - { - await _coursesClient.DeleteCourse(courseId); - return Ok(); - } + [HttpGet("getGroups")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(List), (int)HttpStatusCode.OK)] + public async Task GetGroups(string programName) + { + var groups = await _studentsInfo.GetGroups(programName); + return Ok(groups); + } - [HttpGet("getGroups")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(List), (int)HttpStatusCode.OK)] - public async Task GetGroups(string programName) - { - var groups = await _studentsInfo.GetGroups(programName); - return Ok(groups); - } + [HttpGet("getProgramNames")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(List), (int)HttpStatusCode.OK)] + public async Task GetProgramNames() + { + return Ok(await _studentsInfo.GetProgramNames()); + } - [HttpGet("getProgramNames")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(List), (int)HttpStatusCode.OK)] - public IActionResult GetProgramNames() + [HttpPost("create")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(long), (int)HttpStatusCode.OK)] + public async Task CreateCourse(CreateCourseViewModel model) + { + if (model.GroupNames.Any() && model.FetchStudents) { - return Ok(_studentsInfo.GetProgramNames()); - } + var studentCandidates = new List(); - [HttpPost("create")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(long), (int)HttpStatusCode.OK)] - public async Task CreateCourse(CreateCourseViewModel model) - { - if (!string.IsNullOrEmpty(model.GroupName) && model.FetchStudents) + foreach (var groupName in model.GroupNames) { - var students = _studentsInfo.GetStudentInformation(model.GroupName); - if (students.Count > 0) - { - var sortedStudents = students - .Where(student => !string.IsNullOrEmpty(student.Email)) - .OrderBy(student => student.Surname) - .ThenBy(student => student.Name) - .ToList(); - - var registrationModels = sortedStudents - .Select(student => new RegisterViewModel - { - Email = student.Email, - Name = student.Name, - Surname = student.Surname, - MiddleName = student.MiddleName - }).ToList(); - - var userIds = await AuthServiceClient.GetOrRegisterStudentsBatchAsync(registrationModels); - model.StudentIDs = userIds.Where(x => x.Succeeded).Select(x => x.Value).ToList(); - } + var students = _studentsInfo.GetStudentInformation(groupName); + studentCandidates.AddRange(students); } - model.StudentIDs ??= new List(); - var result = await _coursesClient.CreateCourse(model); - return result.Succeeded - ? Ok(result.Value) as IActionResult - : BadRequest(result.Errors); + var registrationModels = studentCandidates + .Where(student => !string.IsNullOrEmpty(student.Email)) + .OrderBy(student => student.Surname) + .ThenBy(student => student.Name) + .Select(student => new RegisterViewModel + { + Email = student.Email, + Name = student.Name, + Surname = student.Surname, + MiddleName = student.MiddleName + }) + .Distinct() + .ToList(); + + var userIds = await AuthServiceClient.GetOrRegisterStudentsBatchAsync(registrationModels); + + var successfulIds = userIds + .Where(x => x.Succeeded) + .Select(x => x.Value) + .ToList(); + + model.StudentIDs = successfulIds; } - [HttpPost("update/{courseId}")] - [Authorize(Roles = Roles.LecturerRole)] - public async Task UpdateCourse(UpdateCourseViewModel model, long courseId) - { - await _coursesClient.UpdateCourse(model, courseId); - return Ok(); - } + var result = await _coursesClient.CreateCourse(model); + return result.Succeeded + ? Ok(result.Value) + : BadRequest(result.Errors); + } - [HttpPost("signInCourse/{courseId}")] - [Authorize(Roles = Roles.StudentRole)] - public async Task SignInCourse(long courseId) - { - await _coursesClient.SignInCourse(courseId, UserId); - return Ok(); - } + [HttpPost("update/{courseId}")] + [Authorize(Roles = Roles.LecturerRole)] + public async Task UpdateCourse(UpdateCourseViewModel model, long courseId) + { + await _coursesClient.UpdateCourse(model, courseId); + return Ok(); + } - [HttpPost("acceptStudent/{courseId}/{studentId}")] - [Authorize(Roles = Roles.LecturerRole)] - public async Task AcceptStudent(long courseId, string studentId) - { - await _coursesClient.AcceptStudent(courseId, studentId); - return Ok(); - } + [HttpPost("signInCourse/{courseId}")] + [Authorize(Roles = Roles.StudentRole)] + public async Task SignInCourse(long courseId) + { + await _coursesClient.SignInCourse(courseId, UserId); + return Ok(); + } - [HttpPost("rejectStudent/{courseId}/{studentId}")] - [Authorize(Roles = Roles.LecturerRole)] - public async Task RejectStudent(long courseId, string studentId) - { - await _coursesClient.RejectStudent(courseId, studentId); - return Ok(); - } + [HttpPost("acceptStudent/{courseId}/{studentId}")] + [Authorize(Roles = Roles.LecturerRole)] + public async Task AcceptStudent(long courseId, string studentId) + { + await _coursesClient.AcceptStudent(courseId, studentId); + return Ok(); + } - [HttpPost("updateCharacteristics/{courseId}/{studentId}")] - [Authorize(Roles = Roles.LecturerRole)] - public async Task UpdateStudentCharacteristics(long courseId, string studentId, - [FromBody] StudentCharacteristicsDto characteristics) - { - await _coursesClient.UpdateStudentCharacteristics(courseId, studentId, characteristics); - return Ok(); - } + [HttpPost("rejectStudent/{courseId}/{studentId}")] + [Authorize(Roles = Roles.LecturerRole)] + public async Task RejectStudent(long courseId, string studentId) + { + await _coursesClient.RejectStudent(courseId, studentId); + return Ok(); + } - [HttpGet("userCourses")] - [Authorize] - public async Task GetAllUserCourses() - { - var userCourses = await _coursesClient.GetAllUserCourses(); - var result = await GetCoursePreviews(userCourses); - return result; - } + [HttpPost("updateCharacteristics/{courseId}/{studentId}")] + [Authorize(Roles = Roles.LecturerRole)] + public async Task UpdateStudentCharacteristics(long courseId, string studentId, + [FromBody] StudentCharacteristicsDto characteristics) + { + await _coursesClient.UpdateStudentCharacteristics(courseId, studentId, characteristics); + return Ok(); + } - [HttpGet("acceptLecturer/{courseId}/{lecturerEmail}")] - [Authorize(Roles = Roles.LecturerRole)] - public async Task AcceptLecturer(long courseId, string lecturerEmail) - { - var lecturer = await AuthServiceClient.GetAccountDataByEmail(lecturerEmail); - if (lecturer == null) return NotFound("Преподаватель с такой почтой не найден"); - if (lecturer.Role != Roles.LecturerRole && lecturer.Role != Roles.ExpertRole) - return BadRequest("Пользователь не является преподавателем"); - - var result = await _coursesClient.AcceptLecturer(courseId, lecturerEmail, lecturer.UserId); - return result.Succeeded - ? Ok(result) as IActionResult - : BadRequest(result.Errors); - } + [HttpGet("userCourses")] + [Authorize] + public async Task GetAllUserCourses() + { + var userCourses = await _coursesClient.GetAllUserCourses(); + var result = await GetCoursePreviews(userCourses); + return result; + } - [HttpGet("getLecturersAvailableForCourse/{courseId}")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(AccountDataDto[]), (int)HttpStatusCode.OK)] - public async Task GetLecturersAvailableForCourse(long courseId) - { - var result = await _coursesClient.GetLecturersAvailableForCourse(courseId); - return Ok(result.Value); - } + [HttpGet("acceptLecturer/{courseId}/{lecturerEmail}")] + [Authorize(Roles = Roles.LecturerRole)] + public async Task AcceptLecturer(long courseId, string lecturerEmail) + { + var lecturer = await AuthServiceClient.GetAccountDataByEmail(lecturerEmail); + if (lecturer == null) return NotFound("Преподаватель с такой почтой не найден"); + if (lecturer.Role != Roles.LecturerRole && lecturer.Role != Roles.ExpertRole) + return BadRequest("Пользователь не является преподавателем"); + + var result = await _coursesClient.AcceptLecturer(courseId, lecturerEmail, lecturer.UserId); + return result.Succeeded + ? Ok(result) + : BadRequest(result.Errors); + } - [HttpGet("tags/{courseId}")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(string[]), (int)HttpStatusCode.OK)] - public async Task GetAllTagsForCourse(long courseId) - { - var result = await _coursesClient.GetAllTagsForCourse(courseId); - return result.Succeeded - ? Ok(result.Value) as IActionResult - : BadRequest(result.Errors); - } + [HttpGet("getLecturersAvailableForCourse/{courseId}")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(AccountDataDto[]), (int)HttpStatusCode.OK)] + public async Task GetLecturersAvailableForCourse(long courseId) + { + var lecturers = await AuthServiceClient.GetAllLecturers(); + var courseMentors = await _coursesClient.GetCourseLecturersIds(courseId); + var result = lecturers.Where(x => !courseMentors.Contains(x.UserId)); + return Ok(result.ToArray()); + } - [HttpPost("editMentorWorkspace/{courseId}/{mentorId}")] - [Authorize(Roles = Roles.LecturerRole)] - public async Task EditMentorWorkspace( - long courseId, string mentorId, EditMentorWorkspaceDTO editMentorWorkspaceDto) - { - var mentor = await AuthServiceClient.GetAccountData(mentorId); - if (mentor == null) - return NotFound("Пользователь с такой почтой не найден"); + [HttpGet("tags/{courseId}")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(string[]), (int)HttpStatusCode.OK)] + public async Task GetAllTagsForCourse(long courseId) + { + var result = await _coursesClient.GetAllTagsForCourse(courseId); + return result.Succeeded + ? Ok(result.Value) + : BadRequest(result.Errors); + } - if (!Roles.LecturerOrExpertRole.Contains(mentor.Role)) - return BadRequest("Пользователь с такой почтой не является преподавателем или экспертом"); + [HttpPost("editMentorWorkspace/{courseId}/{mentorId}")] + [Authorize(Roles = Roles.LecturerRole)] + public async Task EditMentorWorkspace( + long courseId, string mentorId, EditMentorWorkspaceDTO editMentorWorkspaceDto) + { + var mentor = await AuthServiceClient.GetAccountData(mentorId); + if (mentor == null) + return NotFound("Пользователь с такой почтой не найден"); - var courseFilterModel = _mapper.Map(editMentorWorkspaceDto); - courseFilterModel.UserId = mentorId; + if (!Roles.LecturerOrExpertRole.Contains(mentor.Role)) + return BadRequest("Пользователь с такой почтой не является преподавателем или экспертом"); - var courseFilterCreationResult = - await _coursesClient.CreateOrUpdateCourseFilter(courseId, courseFilterModel); + var courseFilterModel = _mapper.Map(editMentorWorkspaceDto); + courseFilterModel.UserId = mentorId; - return courseFilterCreationResult.Succeeded - ? Ok() as IActionResult - : BadRequest(courseFilterCreationResult.Errors[0]); - } + var courseFilterCreationResult = + await _coursesClient.CreateOrUpdateCourseFilter(courseId, courseFilterModel); - [HttpGet("getMentorWorkspace/{courseId}/{mentorId}")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(WorkspaceViewModel), (int)HttpStatusCode.OK)] - public async Task GetMentorWorkspace(long courseId, string mentorId) - { - var mentor = await AuthServiceClient.GetAccountData(mentorId); - if (mentor == null) - return NotFound("Пользователь с такой почтой не найден"); + return courseFilterCreationResult.Succeeded + ? Ok() + : BadRequest(courseFilterCreationResult.Errors[0]); + } - if (!Roles.LecturerOrExpertRole.Contains(mentor.Role)) - return BadRequest("Пользователь с такой почтой не является преподавателем или экспертом"); + [HttpGet("getMentorWorkspace/{courseId}/{mentorId}")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(WorkspaceViewModel), (int)HttpStatusCode.OK)] + public async Task GetMentorWorkspace(long courseId, string mentorId) + { + var mentor = await AuthServiceClient.GetAccountData(mentorId); + if (mentor == null) + return NotFound("Пользователь с такой почтой не найден"); - var mentorCourseView = await _coursesClient.GetCourseByIdForMentor(courseId, mentorId); - if (!mentorCourseView.Succeeded) - return BadRequest(mentorCourseView.Errors[0]); + if (!Roles.LecturerOrExpertRole.Contains(mentor.Role)) + return BadRequest("Пользователь с такой почтой не является преподавателем или экспертом"); - var studentIds = mentorCourseView.Value.CourseMates.Select(t => t.StudentId).ToArray(); - var students = await AuthServiceClient.GetAccountsData(studentIds); + var mentorCourseView = await _coursesClient.GetCourseByIdForMentor(courseId, mentorId); + if (!mentorCourseView.Succeeded) + return BadRequest(mentorCourseView.Errors[0]); - var workspace = new WorkspaceViewModel - { - Homeworks = mentorCourseView.Value.Homeworks, - Students = students - }; - return Ok(workspace); - } + var studentIds = mentorCourseView.Value.CourseMates.Select(t => t.StudentId).ToArray(); + var students = await AuthServiceClient.GetAccountsData(studentIds); - private async Task ToCourseViewModel(CourseDTO course) + var workspace = new WorkspaceViewModel { - var studentIds = course.CourseMates.Select(t => t.StudentId).ToArray(); - var getStudentsTask = AuthServiceClient.GetAccountsData(studentIds); - var getMentorsTask = AuthServiceClient.GetAccountsData(course.MentorIds); + Homeworks = mentorCourseView.Value.Homeworks, + Students = students.OrderBy(x => x.Surname).ThenBy(x => x.Name).ToArray() + }; + return Ok(workspace); + } - await Task.WhenAll(getStudentsTask, getMentorsTask); + private async Task ToCourseViewModel(CourseDTO course) + { + var studentIds = course.CourseMates.Select(t => t.StudentId).ToArray(); + var getStudentsTask = AuthServiceClient.GetAccountsData(studentIds); + var getMentorsTask = AuthServiceClient.GetAccountsData(course.MentorIds); - var students = getStudentsTask.Result; + await Task.WhenAll(getStudentsTask, getMentorsTask); - var acceptedStudents = new List(); - var newStudents = new List(); - for (var i = 0; i < students.Length; i++) - { - if (!(students[i] is { } student)) continue; - if (course.CourseMates[i].IsAccepted) acceptedStudents.Add(student); - else newStudents.Add(student); - } + var students = getStudentsTask.Result; - return new CourseViewModel - { - Id = course.Id, - Name = course.Name, - GroupName = course.GroupName, - Mentors = getMentorsTask.Result.Where(t => t != null).ToArray(), - AcceptedStudents = acceptedStudents.ToArray(), - NewStudents = newStudents.ToArray(), - Homeworks = course.Homeworks, - IsCompleted = course.IsCompleted, - IsOpen = course.IsOpen, - }; + var acceptedStudents = new List(); + var newStudents = new List(); + for (var i = 0; i < students.Length; i++) + { + if (!(students[i] is { } student)) continue; + if (course.CourseMates[i].IsAccepted) acceptedStudents.Add(student); + else newStudents.Add(student); } + + return new CourseViewModel + { + Id = course.Id, + Name = course.Name, + GroupName = course.GroupName, + Mentors = getMentorsTask.Result.Where(t => t != null).ToArray(), + AcceptedStudents = acceptedStudents.ToArray(), + NewStudents = newStudents.ToArray(), + Homeworks = course.Homeworks, + IsCompleted = course.IsCompleted, + IsOpen = course.IsOpen + }; } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/ExpertsController.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/ExpertsController.cs index 9d5c39049..597159b8e 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/ExpertsController.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/ExpertsController.cs @@ -11,109 +11,108 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace HwProj.APIGateway.API.Controllers +namespace HwProj.APIGateway.API.Controllers; + +[Route("api/[controller]")] +[ApiController] +public class ExpertsController : AggregationController { - [Route("api/[controller]")] - [ApiController] - public class ExpertsController : AggregationController + private readonly ICoursesServiceClient _coursesClient; + private readonly IMapper _mapper; + + public ExpertsController(ICoursesServiceClient coursesClient, + IAuthServiceClient authServiceClient, + IMapper mapper) : base(authServiceClient) + { + _coursesClient = coursesClient; + _mapper = mapper; + } + + [HttpPost("invite")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] + public async Task Invite(InviteExpertViewModel inviteExpertView) + { + var expert = await AuthServiceClient.GetAccountDataByEmail(inviteExpertView.UserEmail); + if (expert == null) + return NotFound("Эксперт с такой почтой не найден"); + + if (expert.Role != Roles.ExpertRole || inviteExpertView.UserId != expert.UserId) + return BadRequest("Пользователь с такой почтой не является экспертом"); + + if (inviteExpertView.UserId != expert.UserId) + return BadRequest("Идентификатор эксперта с такой почтой не соответствует переданному идентификатору"); + + var courseFilterDto = _mapper.Map(inviteExpertView); + + var courseFilterCreationResult = + await _coursesClient.CreateOrUpdateCourseFilter(inviteExpertView.CourseId, courseFilterDto); + if (!courseFilterCreationResult.Succeeded) return BadRequest(courseFilterCreationResult.Errors); + + var acceptanceResult = await _coursesClient.AcceptLecturer(inviteExpertView.CourseId, + inviteExpertView.UserEmail, inviteExpertView.UserId); + return Ok(acceptanceResult); + } + + [HttpPost("register")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] + public async Task Register(RegisterExpertViewModel model) + { + var result = await AuthServiceClient.RegisterExpert(model, UserId); + return Ok(result); + } + + [HttpPost("login")] + [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] + public async Task Login(TokenCredentials credentials) + { + var result = await AuthServiceClient.LoginExpert(credentials).ConfigureAwait(false); + return Ok(result); + } + + [HttpGet("getToken")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] + public async Task GetToken(string expertEmail) + { + var tokenMeta = await AuthServiceClient.GetExpertToken(expertEmail); + return Ok(tokenMeta); + } + + [HttpPost("setProfileIsEdited")] + [Authorize(Roles = Roles.ExpertRole)] + [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] + public async Task SetProfileIsEdited() + { + var result = await AuthServiceClient.SetExpertProfileIsEdited(UserId); + return Ok(result); + } + + [HttpGet("isProfileEdited")] + [Authorize(Roles = Roles.ExpertRole)] + [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] + public async Task GetIsProfileEdited() + { + var result = await AuthServiceClient.GetIsExpertProfileEdited(UserId); + return Ok(result); + } + + [HttpGet("getAll")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(ExpertDataDTO[]), (int)HttpStatusCode.OK)] + public async Task GetAll() + { + var result = await AuthServiceClient.GetAllExperts(); + return Ok(result); + } + + [HttpPost("updateTags")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] + public async Task UpdateTags(UpdateExpertTagsDTO updateExpertTagsDto) { - private readonly ICoursesServiceClient _coursesClient; - private readonly IMapper _mapper; - - public ExpertsController(ICoursesServiceClient coursesClient, - IAuthServiceClient authServiceClient, - IMapper mapper) : base(authServiceClient) - { - _coursesClient = coursesClient; - _mapper = mapper; - } - - [HttpPost("invite")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] - public async Task Invite(InviteExpertViewModel inviteExpertView) - { - var expert = await AuthServiceClient.GetAccountDataByEmail(inviteExpertView.UserEmail); - if (expert == null) - return NotFound("Эксперт с такой почтой не найден"); - - if (expert.Role != Roles.ExpertRole || inviteExpertView.UserId != expert.UserId) - return BadRequest("Пользователь с такой почтой не является экспертом"); - - if (inviteExpertView.UserId != expert.UserId) - return BadRequest("Идентификатор эксперта с такой почтой не соответствует переданному идентификатору"); - - var courseFilterDto = _mapper.Map(inviteExpertView); - - var courseFilterCreationResult = - await _coursesClient.CreateOrUpdateCourseFilter(inviteExpertView.CourseId, courseFilterDto); - if (!courseFilterCreationResult.Succeeded) return BadRequest(courseFilterCreationResult.Errors); - - var acceptanceResult = await _coursesClient.AcceptLecturer(inviteExpertView.CourseId, - inviteExpertView.UserEmail, inviteExpertView.UserId); - return Ok(acceptanceResult); - } - - [HttpPost("register")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] - public async Task Register(RegisterExpertViewModel model) - { - var result = await AuthServiceClient.RegisterExpert(model, UserId); - return Ok(result); - } - - [HttpPost("login")] - [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] - public async Task Login(TokenCredentials credentials) - { - var result = await AuthServiceClient.LoginExpert(credentials).ConfigureAwait(false); - return Ok(result); - } - - [HttpGet("getToken")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] - public async Task GetToken(string expertEmail) - { - var tokenMeta = await AuthServiceClient.GetExpertToken(expertEmail); - return Ok(tokenMeta); - } - - [HttpPost("setProfileIsEdited")] - [Authorize(Roles = Roles.ExpertRole)] - [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] - public async Task SetProfileIsEdited() - { - var result = await AuthServiceClient.SetExpertProfileIsEdited(UserId); - return Ok(result); - } - - [HttpGet("isProfileEdited")] - [Authorize(Roles = Roles.ExpertRole)] - [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] - public async Task GetIsProfileEdited() - { - var result = await AuthServiceClient.GetIsExpertProfileEdited(UserId); - return Ok(result); - } - - [HttpGet("getAll")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(ExpertDataDTO[]), (int)HttpStatusCode.OK)] - public async Task GetAll() - { - var result = await AuthServiceClient.GetAllExperts(); - return Ok(result); - } - - [HttpPost("updateTags")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] - public async Task UpdateTags(UpdateExpertTagsDTO updateExpertTagsDto) - { - var result = await AuthServiceClient.UpdateExpertTags(UserId, updateExpertTagsDto); - return Ok(result); - } + var result = await AuthServiceClient.UpdateExpertTags(UserId, updateExpertTagsDto); + return Ok(result); } -} \ No newline at end of file +} diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/FilesController.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/FilesController.cs index a47646ee7..6ee73f136 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/FilesController.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/FilesController.cs @@ -4,73 +4,88 @@ using HwProj.AuthService.Client; using HwProj.ContentService.Client; using HwProj.Models.ContentService.DTO; -using HwProj.Models.Roles; +using HwProj.Models.CourseUnitType; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace HwProj.APIGateway.API.Controllers +namespace HwProj.APIGateway.API.Controllers; + +[Route("api/[controller]")] +[Authorize] +[ApiController] +public class FilesController( + IAuthServiceClient authServiceClient, + IContentServiceClient contentServiceClient, + FilesPrivacyFilter privacyFilter, + FilesCountLimiter filesCountLimiter) + : AggregationController(authServiceClient) { - [Route("api/[controller]")] - [Authorize] - [ApiController] - public class FilesController : AggregationController + [HttpPost("process")] + [ProducesResponseType((int)HttpStatusCode.OK)] + [ProducesResponseType((int)HttpStatusCode.Forbidden)] + [ProducesResponseType(typeof(string[]), (int)HttpStatusCode.BadRequest)] + public async Task Process([FromForm] ProcessFilesDTO processFilesDto) { - private readonly IContentServiceClient _contentServiceClient; + var checkRights = await privacyFilter.CheckUploadRights(UserId, processFilesDto.FilesScope); + if (!checkRights) return Forbid("Недостаточно прав для загрузки файлов"); - public FilesController(IAuthServiceClient authServiceClient, - IContentServiceClient contentServiceClient) : base(authServiceClient) - { - _contentServiceClient = contentServiceClient; - } + var checkCountLimit = await filesCountLimiter.CheckCountLimit(processFilesDto); + if (!checkCountLimit) + return Forbid("Слишком много файлов в решении." + + $"Максимальное количество файлов - ${FilesCountLimiter.MaxSolutionFiles}"); - [HttpPost("upload")] - [Authorize(Roles = Roles.LecturerRole)] - [ServiceFilter(typeof(CourseMentorOnlyAttribute))] - [ProducesResponseType((int)HttpStatusCode.OK)] - [ProducesResponseType(typeof(string[]), (int)HttpStatusCode.BadRequest)] - [ProducesResponseType(typeof(string[]), (int)HttpStatusCode.ServiceUnavailable)] - public async Task Upload([FromForm] UploadFileDTO uploadFileDto) - { - var result = await _contentServiceClient.UploadFileAsync(uploadFileDto); - return result.Succeeded - ? Ok() as IActionResult - : StatusCode((int)HttpStatusCode.ServiceUnavailable, result.Errors); - } + var result = await contentServiceClient.ProcessFilesAsync(processFilesDto); + return result.Succeeded + ? Ok() + : BadRequest(result.Errors); + } - [HttpGet("downloadLink")] - [ProducesResponseType(typeof(string), (int)HttpStatusCode.OK)] - [ProducesResponseType(typeof(string[]), (int)HttpStatusCode.NotFound)] - public async Task GetDownloadLink([FromQuery] string key) - { - var result = await _contentServiceClient.GetDownloadLinkAsync(key); - return result.Succeeded - ? Ok(result.Value) as IActionResult - : NotFound(result.Errors); - } + [HttpPost("statuses")] + [ProducesResponseType((int)HttpStatusCode.Forbidden)] + [ProducesResponseType(typeof(FileInfoDTO[]), (int)HttpStatusCode.OK)] + [ProducesResponseType(typeof(string[]), (int)HttpStatusCode.BadRequest)] + public async Task GetStatuses(ScopeDTO filesScope) + { + var checkRights = await privacyFilter.CheckUploadRights(UserId, filesScope); + if (!checkRights) return Forbid("Недостаточно прав для получения информации о файлах"); - [HttpGet("filesInfo/{courseId}")] - [ProducesResponseType(typeof(FileInfoDTO[]), (int)HttpStatusCode.OK)] - [ProducesResponseType(typeof(string[]), (int)HttpStatusCode.ServiceUnavailable)] - public async Task GetFilesInfo(long courseId, [FromQuery] long? homeworkId = null) - { - var filesInfoResult = await _contentServiceClient.GetFilesInfo(courseId, homeworkId); - return filesInfoResult.Succeeded - ? Ok(filesInfoResult.Value) as IActionResult - : StatusCode((int)HttpStatusCode.ServiceUnavailable, filesInfoResult.Errors); - } + var result = await contentServiceClient.GetFilesStatuses(filesScope); + return result.Succeeded + ? Ok(result.Value) + : BadRequest(result.Errors); + } + + [HttpGet("downloadLink")] + [ProducesResponseType((int)HttpStatusCode.Forbidden)] + [ProducesResponseType(typeof(string), (int)HttpStatusCode.OK)] + [ProducesResponseType(typeof(string[]), (int)HttpStatusCode.NotFound)] + public async Task GetDownloadLink([FromQuery] long fileId) + { + var linkDto = await contentServiceClient.GetDownloadLinkAsync(fileId); + if (!linkDto.Succeeded) return BadRequest(linkDto.Errors); + + var result = linkDto.Value; + var userId = UserId; - [HttpDelete] - [Authorize(Roles = Roles.LecturerRole)] - [ServiceFilter(typeof(CourseMentorOnlyAttribute))] - [ProducesResponseType((int)HttpStatusCode.OK)] - [ProducesResponseType(typeof(string[]), (int)HttpStatusCode.BadRequest)] - [ProducesResponseType(typeof(string[]), (int)HttpStatusCode.NotFound)] - public async Task DeleteFile([FromQuery] long courseId, [FromQuery] string key) + foreach (var scope in result.FileScopes) { - var deletionResult = await _contentServiceClient.DeleteFileAsync(key); - return deletionResult.Succeeded - ? Ok() as IActionResult - : NotFound(deletionResult.Errors); + if (await privacyFilter.CheckDownloadRights(userId, scope)) + return Ok(result.DownloadUrl); } + + return Forbid("Недостаточно прав для получения ссылки на файл"); + } + + [HttpGet("info/course/{courseId}")] + [ProducesResponseType(typeof(FileInfoDTO[]), (int)HttpStatusCode.OK)] + [ProducesResponseType(typeof(string[]), (int)HttpStatusCode.BadRequest)] + public async Task GetFilesInfo(long courseId, + [FromQuery] bool uploadedOnly = true, + [FromQuery] string courseUnitType = CourseUnitType.Homework) + { + var filesInfoResult = await contentServiceClient.GetFilesInfo(courseId, uploadedOnly, courseUnitType); + return filesInfoResult.Succeeded + ? Ok(filesInfoResult.Value) + : BadRequest(filesInfoResult.Errors); } -} \ No newline at end of file +} diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/HomeworksController.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/HomeworksController.cs index 52eb39be0..6f871d362 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/HomeworksController.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/HomeworksController.cs @@ -7,63 +7,62 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace HwProj.APIGateway.API.Controllers +namespace HwProj.APIGateway.API.Controllers; + +[Route("api/[controller]")] +[ApiController] +public class HomeworksController : ControllerBase { - [Route("api/[controller]")] - [ApiController] - public class HomeworksController : ControllerBase - { - private readonly ICoursesServiceClient _coursesClient; + private readonly ICoursesServiceClient _coursesClient; - public HomeworksController(ICoursesServiceClient coursesClient) - { - _coursesClient = coursesClient; - } + public HomeworksController(ICoursesServiceClient coursesClient) + { + _coursesClient = coursesClient; + } - [HttpGet("get/{homeworkId}")] - [Authorize] - [ProducesResponseType(typeof(HomeworkViewModel), (int)HttpStatusCode.OK)] - public async Task GetHomework(long homeworkId) - { - var result = await _coursesClient.GetHomework(homeworkId); - return Ok(result); - } + [HttpGet("get/{homeworkId}")] + [Authorize] + [ProducesResponseType(typeof(HomeworkViewModel), (int)HttpStatusCode.OK)] + public async Task GetHomework(long homeworkId) + { + var result = await _coursesClient.GetHomework(homeworkId); + return Ok(result); + } - [HttpGet("getForEditing/{homeworkId}")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(HomeworkViewModel), (int)HttpStatusCode.OK)] - public async Task GetForEditingHomework(long homeworkId) - { - var result = await _coursesClient.GetForEditingHomework(homeworkId); - return Ok(result); - } + [HttpGet("getForEditing/{homeworkId}")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(HomeworkViewModel), (int)HttpStatusCode.OK)] + public async Task GetForEditingHomework(long homeworkId) + { + var result = await _coursesClient.GetForEditingHomework(homeworkId); + return Ok(result); + } - [HttpPost("{courseId}/add")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(long), (int)HttpStatusCode.OK)] - public async Task AddHomework(CreateHomeworkViewModel homeworkViewModel, long courseId) - { - var result = await _coursesClient.AddHomeworkToCourse(homeworkViewModel, courseId); - return result.Succeeded - ? Ok(result.Value) as IActionResult - : BadRequest(result.Errors); - } + [HttpPost("{courseId}/add")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] + public async Task AddHomework(CreateHomeworkViewModel homeworkViewModel, long courseId) + { + var result = await _coursesClient.AddHomeworkToCourse(homeworkViewModel, courseId); + return result.Succeeded + ? Ok(result) + : BadRequest(result); + } - [HttpDelete("delete/{homeworkId}")] - [Authorize(Roles = Roles.LecturerRole)] - public async Task DeleteHomework(long homeworkId) - { - await _coursesClient.DeleteHomework(homeworkId); - return Ok(); - } + [HttpDelete("delete/{homeworkId}")] + [Authorize(Roles = Roles.LecturerRole)] + public async Task DeleteHomework(long homeworkId) + { + await _coursesClient.DeleteHomework(homeworkId); + return Ok(); + } - [HttpPut("update/{homeworkId}")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] - public async Task UpdateHomework(long homeworkId, CreateHomeworkViewModel homeworkViewModel) - { - var result = await _coursesClient.UpdateHomework(homeworkId, homeworkViewModel); - return Ok(result); - } + [HttpPut("update/{homeworkId}")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] + public async Task UpdateHomework(long homeworkId, CreateHomeworkViewModel homeworkViewModel) + { + var result = await _coursesClient.UpdateHomework(homeworkId, homeworkViewModel); + return Ok(result); } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/NotificationsController.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/NotificationsController.cs index c8a3ef536..8a4dc0a89 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/NotificationsController.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/NotificationsController.cs @@ -1,66 +1,65 @@ using System; -using HwProj.Models.NotificationsService; -using HwProj.NotificationsService.Client; -using Microsoft.AspNetCore.Mvc; using System.Net; using System.Threading.Tasks; +using HwProj.Models.NotificationsService; using HwProj.Models.Roles; +using HwProj.NotificationsService.Client; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; -namespace HwProj.APIGateway.API.Controllers +namespace HwProj.APIGateway.API.Controllers; + +[Route("api/[controller]")] +[Authorize] +[ApiController] +public class NotificationsController : AggregationController { - [Route("api/[controller]")] - [Authorize] - [ApiController] - public class NotificationsController : AggregationController - { - private readonly INotificationsServiceClient _notificationsClient; + private readonly INotificationsServiceClient _notificationsClient; - public NotificationsController(INotificationsServiceClient notificationsClient) : base(null) - { - _notificationsClient = notificationsClient; - } + public NotificationsController(INotificationsServiceClient notificationsClient) : base(null) + { + _notificationsClient = notificationsClient; + } - [HttpGet("getNewNotificationsCount")] - public async Task GetNewNotificationsCount() - { - var count = await _notificationsClient.GetNewNotificationsCount(UserId); - return count; - } + [HttpGet("getNewNotificationsCount")] + public async Task GetNewNotificationsCount() + { + var count = await _notificationsClient.GetNewNotificationsCount(UserId); + return count; + } - [HttpGet("get")] - [ProducesResponseType(typeof(CategorizedNotifications[]), (int)HttpStatusCode.OK)] - public async Task Get() - { - var result = await _notificationsClient.Get(UserId); - return Ok(result); - } + [HttpGet("get")] + [ProducesResponseType(typeof(CategorizedNotifications[]), (int)HttpStatusCode.OK)] + public async Task Get() + { + var result = await _notificationsClient.Get(UserId); + return Ok(result); + } - [HttpPut("markAsSeen")] - public async Task MarkAsSeen([FromBody] long[] notificationIds) - { - await _notificationsClient.MarkAsSeen(UserId, notificationIds); - return Ok(); - } + [HttpPut("markAsSeen")] + public async Task MarkAsSeen([FromBody] long[] notificationIds) + { + await _notificationsClient.MarkAsSeen(UserId, notificationIds); + return Ok(); + } - [HttpGet("settings")] - [Authorize] - [ProducesResponseType(typeof(NotificationsSettingDto[]), (int)HttpStatusCode.OK)] - public async Task GetSettings() - { - var isLecturer = User.IsInRole(Roles.LecturerRole); - if (!isLecturer) return Ok(Array.Empty()); + [HttpGet("settings")] + [Authorize] + [ProducesResponseType(typeof(NotificationsSettingDto[]), (int)HttpStatusCode.OK)] + public async Task GetSettings() + { + var isLecturer = User.IsInRole(Roles.LecturerRole); + if (!isLecturer) return Ok(Array.Empty()); - var settings = await _notificationsClient.GetSettings(UserId); - return Ok(settings); - } + var settings = await _notificationsClient.GetSettings(UserId); + return Ok(settings); + } - [HttpPut("settings")] - [Authorize] - public async Task ChangeSetting(NotificationsSettingDto newSetting) - { - await _notificationsClient.ChangeSetting(UserId, newSetting); - return Ok(); - } + [HttpPut("settings")] + [Authorize] + public async Task ChangeSetting(NotificationsSettingDto newSetting) + { + await _notificationsClient.ChangeSetting(UserId, newSetting); + return Ok(); } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/SolutionsController.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/SolutionsController.cs index cb1793305..1ab2fe869 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/SolutionsController.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/SolutionsController.cs @@ -4,10 +4,10 @@ using System.Net; using System.Threading.Tasks; using HwProj.APIGateway.API.ExceptionFilters; -using HwProj.APIGateway.API.Extensions; using HwProj.APIGateway.API.Models.Solutions; using HwProj.AuthService.Client; using HwProj.CoursesService.Client; +using HwProj.Models.AuthService.DTO; using HwProj.Models.CoursesService; using HwProj.Models.CoursesService.DTO; using HwProj.Models.CoursesService.ViewModels; @@ -17,279 +17,299 @@ using HwProj.SolutionsService.Client; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using PostSolutionModel = HwProj.APIGateway.API.Models.Solutions.PostSolutionModel; -namespace HwProj.APIGateway.API.Controllers +namespace HwProj.APIGateway.API.Controllers; + +[Route("api/[controller]")] +[ApiController] +[ForbiddenExceptionFilter] +public class SolutionsController : AggregationController { - [Route("api/[controller]")] - [ApiController] - [ForbiddenExceptionFilter] - public class SolutionsController : AggregationController - { - private readonly ISolutionsServiceClient _solutionsClient; - private readonly ICoursesServiceClient _coursesServiceClient; + private readonly ICoursesServiceClient _coursesServiceClient; + private readonly ISolutionsServiceClient _solutionsClient; - public SolutionsController(ISolutionsServiceClient solutionsClient, IAuthServiceClient authServiceClient, - ICoursesServiceClient coursesServiceClient) : - base(authServiceClient) - { - _solutionsClient = solutionsClient; - _coursesServiceClient = coursesServiceClient; - } + public SolutionsController(ISolutionsServiceClient solutionsClient, IAuthServiceClient authServiceClient, + ICoursesServiceClient coursesServiceClient) : + base(authServiceClient) + { + _solutionsClient = solutionsClient; + _coursesServiceClient = coursesServiceClient; + } - [HttpGet("{solutionId}")] - [ProducesResponseType(typeof(Solution), (int)HttpStatusCode.OK)] - public async Task GetSolutionById(long solutionId) - { - var result = await _solutionsClient.GetSolutionById(solutionId); - return result == null - ? NotFound() as IActionResult - : Ok(result); - } + [HttpGet("{solutionId}")] + [ProducesResponseType(typeof(Solution), (int)HttpStatusCode.OK)] + public async Task GetSolutionById(long solutionId) + { + var result = await _solutionsClient.GetSolutionById(solutionId); + return result == null + ? NotFound() + : Ok(result); + } - [HttpGet("taskSolution/{taskId}/{studentId}")] - [Authorize] - [ProducesResponseType(typeof(UserTaskSolutionsPageData), (int)HttpStatusCode.OK)] - public async Task GetStudentSolution(long taskId, string studentId) + [HttpGet("taskSolution/{taskId}/{studentId}")] + [Authorize] + [ProducesResponseType(typeof(UserTaskSolutionsPageData), (int)HttpStatusCode.OK)] + public async Task GetStudentSolution(long taskId, string studentId) + { + var course = await _coursesServiceClient.GetCourseByTask(taskId); + if (course == null) return NotFound(); + + var courseMate = course.AcceptedStudents.FirstOrDefault(t => t.StudentId == studentId); + if (courseMate == null) return NotFound(); + + var studentSolutions = (await _solutionsClient.GetCourseStatistics(course.Id, UserId)) + .Single().Homeworks + .ToDictionary(x => x.Id); + + var homeworks = course.Homeworks + .Where(t => t.Tasks.Any()) + .GroupBy(GetGroupingKey) + .ToList(); + + var tasks = homeworks + .SelectMany(x => x.SelectMany(t => t.Tasks)) + .ToDictionary(t => t.Id); + + // Получаем группы только для выбранной задачи + var studentsOnCourse = course.AcceptedStudents + .Select(t => t.StudentId) + .ToArray(); + + var mentorIds = studentSolutions.Values + .SelectMany(t => t.Tasks) + .SelectMany(t => t.Solution) + .Select(t => t.LecturerId ?? "") + .Where(x => x != "") + .Distinct() + .ToArray(); + + var accounts = await AuthServiceClient.GetAccountsData(studentsOnCourse.Union(mentorIds).ToArray()); + + var solutionsGroupsIds = studentSolutions.Values + .SelectMany(t => t.Tasks) + .First(x => x.Id == taskId).Solution + .Select(s => s.GroupId) + .Distinct() + .ToList(); + + var accountsCache = accounts.ToDictionary(dto => dto.UserId); + + var solutionsGroups = course.Groups + .Where(g => solutionsGroupsIds.Contains(g.Id)) + .ToDictionary(t => t.Id); + + var taskSolutions = homeworks.Select(group => { - var course = await _coursesServiceClient.GetCourseByTask(taskId); - if (course == null) return NotFound(); - - var courseMate = course.AcceptedStudents.FirstOrDefault(t => t.StudentId == studentId); - if (courseMate == null) return NotFound(); - - var studentSolutions = (await _solutionsClient.GetCourseStatistics(course.Id, UserId)) - .Single().Homeworks - .ToDictionary(x => x.Id); - - var homeworks = course.Homeworks - .Where(t => t.Tasks.Any()) - .GroupBy(GetGroupingKey) - .ToList(); - - var tasks = homeworks - .SelectMany(x => x.SelectMany(t => t.Tasks)) - .ToDictionary(t => t.Id); - - // Получаем группы только для выбранной задачи - var studentsOnCourse = course.AcceptedStudents - .Select(t => t.StudentId) - .ToArray(); - - var mentorIds = studentSolutions.Values - .SelectMany(t => t.Tasks) - .SelectMany(t => t.Solution) - .Select(t => t.LecturerId ?? "") - .Where(x => x != "") - .Distinct() - .ToArray(); - - var accounts = await AuthServiceClient.GetAccountsData(studentsOnCourse.Union(mentorIds).ToArray()); - - var solutionsGroupsIds = studentSolutions.Values - .SelectMany(t => t.Tasks) - .First(x => x.Id == taskId).Solution - .Select(s => s.GroupId) - .Distinct() - .ToList(); - - var accountsCache = accounts.ToDictionary(dto => dto.UserId); - - var solutionsGroups = course.Groups - .Where(g => solutionsGroupsIds.Contains(g.Id)) - .ToDictionary(t => t.Id); - - var taskSolutions = homeworks.Select(group => + var isSingle = group.Count() == 1; + return new HomeworksGroupUserTaskSolutions { - var isSingle = group.Count() == 1; - return new HomeworksGroupUserTaskSolutions - { - GroupTitle = isSingle ? null : group.Key.id, - HomeworkSolutions = group.Select(h => + GroupTitle = isSingle ? null : group.Key.id, + HomeworkSolutions = group.Select(h => + { + studentSolutions.TryGetValue(h.Id, out var solutions); + return new HomeworkUserTaskSolutions { - studentSolutions.TryGetValue(h.Id, out var solutions); - return new HomeworkUserTaskSolutions - { - HomeworkTitle = h.Title, - StudentSolutions = solutions!.Tasks.Select(t => + HomeworkTitle = h.Title, + StudentSolutions = solutions!.Tasks.Select(t => + { + var task = tasks[t.Id]; + return new UserTaskSolutions2 { - var task = tasks[t.Id]; - return new UserTaskSolutions2 - { - MaxRating = task.MaxRating, - Title = task.Title, - Tags = task.Tags, - TaskId = task.Id.ToString(), - Solutions = t.Solution.Select(s => new GetSolutionModel(s, - s.TaskId == taskId && s.GroupId is { } groupId - ? solutionsGroups[groupId].StudentsIds - .Select(x => accountsCache[x]) - .ToArray() - : null, - s.LecturerId == null ? null : accountsCache[s.LecturerId])).ToArray() - }; - }) - .ToArray() - }; - }) - .ToArray() - }; - }).ToArray(); + MaxRating = task.MaxRating, + Title = task.Title, + Tags = task.Tags, + TaskId = task.Id.ToString(), + Solutions = t.Solution.Select(s => new GetSolutionModel(s, + s.TaskId == taskId && s.GroupId is { } groupId + ? solutionsGroups[groupId].StudentsIds + .Select(x => accountsCache[x]) + .ToArray() + : null, + s.LecturerId == null ? null : accountsCache[s.LecturerId])).ToArray() + }; + }) + .ToArray() + }; + }) + .ToArray() + }; + }).ToArray(); - return Ok(new UserTaskSolutionsPageData() - { - CourseId = course.Id, - CourseMates = accounts, - TaskSolutions = taskSolutions - }); - } + return Ok(new UserTaskSolutionsPageData + { + CourseId = course.Id, + CourseMates = accounts, + TaskSolutions = taskSolutions + }); + } - // Научить без конкретного taskId по courseId получать данные - [Authorize] - [HttpGet("tasks/{taskId}")] - [ProducesResponseType(typeof(TaskSolutionStatisticsPageData), (int)HttpStatusCode.OK)] - public async Task GetTaskSolutionsPageData(long taskId) + // Научить без конкретного taskId по courseId получать данные + [Authorize] + [HttpGet("tasks/{taskId}")] + [ProducesResponseType(typeof(TaskSolutionStatisticsPageData), (int)HttpStatusCode.OK)] + public async Task GetTaskSolutionsPageData(long taskId, string? secondMentorId = null) + { + var course = await _coursesServiceClient.GetCourseByTask(taskId); + //TODO: CourseMentorOnlyAttribute + if (course == null || !course.MentorIds.Contains(UserId)) return Forbid(); + + var students = course.AcceptedStudents.ToDictionary(x => x.StudentId); + var secondMentorStudentIds = new HashSet(); + if (secondMentorId != null && course.MentorIds.Contains(secondMentorId)) { - var course = await _coursesServiceClient.GetCourseByTask(taskId); - //TODO: CourseMentorOnlyAttribute - if (course == null || !course.MentorIds.Contains(UserId)) return Forbid(); + var secondMentorCourseResult = + await _coursesServiceClient.GetCourseByIdForMentor(course.Id, secondMentorId); + if (!secondMentorCourseResult.Succeeded) return BadRequest(secondMentorCourseResult.Errors); - var students = course.AcceptedStudents.ToDictionary(x => x.StudentId); - var studentIds = students.Keys.ToArray(); + foreach (var student in secondMentorCourseResult.Value.AcceptedStudents) + { + secondMentorStudentIds.Add(student.StudentId); + students.TryAdd(student.StudentId, student); + } + } - var currentDateTime = DateTime.UtcNow; - var actualHomeworks = course.Homeworks - .Select(hw => - { - hw.Tasks = hw.Tasks.Where(t => t.PublicationDate <= currentDateTime).ToList(); - return hw; - }) - .Where(hw => hw.Tasks.Count > 0) - .ToList(); - - var homeworks = actualHomeworks - .GroupBy(GetGroupingKey) - .ToList(); - - var homeworksGroup = homeworks - .First(g => g.Any(h => h.Tasks.Any(t => t.Id == taskId))) - .ToList(); - - var homeworkIndex = homeworksGroup.FindIndex(t => t.Tasks.Any(x => x.Id == taskId)); - var taskIndex = homeworksGroup[homeworkIndex].Tasks.FindIndex(t => t.Id == taskId); - var taskVersionIds = homeworksGroup.Select(h => h.Tasks[taskIndex].Id).ToArray(); - - var taskIds = homeworks - .SelectMany(x => x.SelectMany(t => t.Tasks)) - .Select(t => t.Id) - .ToArray(); - - var getUsersDataTask = AuthServiceClient.GetAccountsData(studentIds.Union(course.MentorIds).ToArray()); - var getStatisticsTasks = - taskVersionIds.Select(x => _solutionsClient.GetTaskSolutionStatistics(course.Id, x)).ToList(); - var getStatsForTasks = _solutionsClient.GetTaskSolutionsStats( - new GetTasksSolutionsModel - { - StudentIds = studentIds, - TaskIds = taskIds - }); + var studentIds = students.Keys.ToArray(); - await Task.WhenAll(getUsersDataTask, Task.WhenAll(getStatisticsTasks), getStatsForTasks); + var currentDateTime = DateTime.UtcNow; + var actualHomeworks = course.Homeworks + .Select(hw => + { + hw.Tasks = hw.Tasks.Where(t => t.PublicationDate <= currentDateTime).ToList(); + return hw; + }) + .Where(hw => hw.Tasks.Count > 0) + .ToList(); + + var homeworks = actualHomeworks + .GroupBy(GetGroupingKey) + .ToList(); + + var homeworksGroup = homeworks + .First(g => g.Any(h => h.Tasks.Any(t => t.Id == taskId))) + .ToList(); + + var homeworkIndex = homeworksGroup.FindIndex(t => t.Tasks.Any(x => x.Id == taskId)); + var taskIndex = homeworksGroup[homeworkIndex].Tasks.FindIndex(t => t.Id == taskId); + var taskVersionIds = homeworksGroup.Select(h => h.Tasks[taskIndex].Id).ToArray(); + + var taskIds = homeworks + .SelectMany(x => x.SelectMany(t => t.Tasks)) + .Select(t => t.Id) + .ToArray(); + + var getUsersDataTask = AuthServiceClient.GetAccountsData(studentIds.Union(course.MentorIds).ToArray()); + var getStatisticsTasks = + taskVersionIds.Select(x => _solutionsClient.GetTaskSolutionStatistics(course.Id, x)).ToList(); + var getStatsForTasks = _solutionsClient.GetTaskSolutionsStats( + new GetTasksSolutionsModel + { + StudentIds = studentIds, + TaskIds = taskIds + }); + + await Task.WhenAll(getUsersDataTask, Task.WhenAll(getStatisticsTasks), getStatsForTasks); - var usersData = getUsersDataTask.Result.ToDictionary(t => t.UserId); - var statistics = taskVersionIds - .Zip(getStatisticsTasks, - (id, solutions) => (id, statistic: solutions.Result.ToDictionary(t => t.StudentId))) - .ToDictionary(tuple => tuple.id, tuple => tuple.statistic); + var usersData = getUsersDataTask.Result.ToDictionary(t => t.UserId); + var statistics = taskVersionIds + .Zip(getStatisticsTasks, + (id, solutions) => (id, statistic: solutions.Result.ToDictionary(t => t.StudentId))) + .ToDictionary(tuple => tuple.id, tuple => tuple.statistic); - var statsForTasks = getStatsForTasks.Result.ToDictionary(t => t.TaskId); - var groups = course.Groups.ToDictionary( - t => t.Id, - t => t.StudentsIds.Select(s => usersData[s]).ToArray()); + var statsForTasks = getStatsForTasks.Result.ToDictionary(t => t.TaskId); + var groups = course.Groups.ToDictionary( + t => t.Id, + t => t.StudentsIds.Select(s => usersData[s]).ToArray()); - var result = new TaskSolutionStatisticsPageData() + var result = new TaskSolutionStatisticsPageData + { + CourseId = course.Id, + TaskSolutions = taskVersionIds.Select(tId => { - CourseId = course.Id, - TaskSolutions = taskVersionIds.Select(tId => + statistics.TryGetValue(tId, out var statistic); + return new TaskSolutions { - statistics.TryGetValue(tId, out var statistic); - return new TaskSolutions - { - TaskId = tId, - StudentSolutions = studentIds.Select(studentId => new UserTaskSolutions + TaskId = tId, + StudentSolutions = studentIds.Select(studentId => new UserTaskSolutions + { + Solutions = statistic!.TryGetValue(studentId, out var studentSolutions) + ? studentSolutions.Solutions.Select(t => new GetSolutionModel(t, + t.GroupId is { } groupId ? groups[groupId] : null, + t.LecturerId == null ? null : usersData[t.LecturerId])).ToArray() + : Array.Empty(), + Student = new StudentDataDto(usersData[studentId]) { - Solutions = statistic!.TryGetValue(studentId, out var studentSolutions) - ? studentSolutions.Solutions.Select(t => new GetSolutionModel(t, - t.GroupId is { } groupId ? groups[groupId] : null, - t.LecturerId == null ? null : usersData[t.LecturerId])).ToArray() - : Array.Empty(), - Student = new StudentDataDto(usersData[studentId]) - { - Characteristics = students[studentId].Characteristics, - } - }) - .OrderBy(t => t.Student.Surname) - .ThenBy(t => t.Student.Name) - .ToArray(), - }; - }).ToArray(), - StatsForTasks = homeworks.Select(group => + Characteristics = students[studentId].Characteristics + }, + HasDifferentReviewer = secondMentorStudentIds.Contains(studentId) + }) + .OrderBy(x => !x.HasDifferentReviewer) + .ThenBy(t => t.Student.Surname) + .ThenBy(t => t.Student.Name) + .ToArray() + }; + }).ToArray(), + StatsForTasks = homeworks.Select(group => + { + var isSingle = homeworks.Count == 1; + return new HomeworksGroupSolutionStats { - var isSingle = homeworks.Count == 1; - return new HomeworksGroupSolutionStats() + GroupTitle = isSingle ? null : group.Key.id, + StatsForHomeworks = group.Select(h => new HomeworkSolutionsStats { - GroupTitle = isSingle ? null : group.Key.id, - StatsForHomeworks = group.Select(h => new HomeworkSolutionsStats + HomeworkTitle = h.Title, + StatsForTasks = h.Tasks.Select(t => { - HomeworkTitle = h.Title, - StatsForTasks = h.Tasks.Select(t => - { - var stats = statsForTasks.TryGetValue(t.Id, out var taskStats) - ? taskStats - : new TaskSolutionsStats(); - - stats.Title = t.Title; - stats.Tags = t.Tags; - return stats; - }).ToArray() + var stats = statsForTasks.TryGetValue(t.Id, out var taskStats) + ? taskStats + : new TaskSolutionsStats(); + + stats.Title = t.Title; + stats.Tags = t.Tags; + return stats; }).ToArray() - }; - }).ToArray() - }; + }).ToArray() + }; + }).ToArray(), - return Ok(result); - } + CourseMentors = course.MentorIds.Select(t => usersData[t]).ToArray() + }; - [HttpPost("{taskId}")] - [Authorize(Roles = Roles.StudentRole)] - [ProducesResponseType(typeof(long), (int)HttpStatusCode.OK)] - public async Task PostSolution(SolutionViewModel model, long taskId) - { - var solutionModel = new PostSolutionModel(model) - { - StudentId = UserId - }; + return Ok(result); + } - var course = await _coursesServiceClient.GetCourseByTask(taskId); - if (course is null) return BadRequest(); + [HttpPost("{taskId}")] + [Authorize(Roles = Roles.StudentRole)] + [ProducesResponseType(typeof(long), (int)HttpStatusCode.OK)] + public async Task PostSolution(PostSolutionModel model, long taskId) + { + var solutionModel = new HwProj.Models.SolutionsService.PostSolutionModel + { + GithubUrl = model.GithubUrl, + Comment = model.Comment, + StudentId = UserId + }; - var courseMate = course.AcceptedStudents.FirstOrDefault(t => t.StudentId == solutionModel.StudentId); - if (courseMate == null) return BadRequest($"Студента с id {solutionModel.StudentId} не существует"); + var course = await _coursesServiceClient.GetCourseByTask(taskId); + if (course is null) return BadRequest(); - if (model.GroupMateIds == null || model.GroupMateIds.Length == 0) - { - var result = await _solutionsClient.PostSolution(taskId, solutionModel); - return Ok(result); - } + var courseMate = course.AcceptedStudents.FirstOrDefault(t => t.StudentId == solutionModel.StudentId); + if (courseMate == null) return BadRequest($"Студента с id {solutionModel.StudentId} не существует"); + if (model.GroupMateIds == null || model.GroupMateIds.Length == 0) + { + var result = await _solutionsClient.PostSolution(taskId, solutionModel); + return Ok(result); + } + else + { var fullStudentsGroup = model.GroupMateIds.ToList(); fullStudentsGroup.Add(solutionModel.StudentId); var arrFullStudentsGroup = fullStudentsGroup.Distinct().ToArray(); if (arrFullStudentsGroup.Intersect(course.CourseMates.Select(x => x.StudentId)).Count() != arrFullStudentsGroup.Length) - { return BadRequest(); - } var existedGroup = course.Groups.SingleOrDefault(x => x.StudentsIds.Length == arrFullStudentsGroup.Length && @@ -300,206 +320,266 @@ public async Task PostSolution(SolutionViewModel model, long task await _coursesServiceClient.CreateCourseGroup(new CreateGroupViewModel(arrFullStudentsGroup, course.Id), taskId); - await _solutionsClient.PostSolution(taskId, solutionModel); + var result = await _solutionsClient.PostSolution(taskId, solutionModel); - return Ok(solutionModel); + return Ok(result); } + } - [HttpPost("rateEmptySolution/{taskId}")] - [Authorize(Roles = Roles.LecturerOrExpertRole)] - public async Task PostEmptySolutionWithRate(long taskId, SolutionViewModel solution) - { - var course = await _coursesServiceClient.GetCourseByTask(taskId); - if (course == null || !course.MentorIds.Contains(UserId)) return Forbid(); - if (course.CourseMates.All(t => t.StudentId != solution.StudentId)) - return BadRequest($"Студент с id {solution.StudentId} не записан на курс"); - - solution.Comment = "[Решение было сдано вне сервиса]"; - await _solutionsClient.PostEmptySolutionWithRate(taskId, solution); - return Ok(); - } + [HttpPost("automated/{courseId}")] + [Authorize(Roles = Roles.LecturerOrExpertRole)] + [ProducesResponseType(typeof(void), (int)HttpStatusCode.OK)] + public async Task PostAutomatedSolution(PostAutomatedSolutionModel model, long courseId) + { + var course = await _coursesServiceClient.GetCourseById(courseId); + if (course is null) return BadRequest($"Курс с Id {courseId} не найден"); + if (!course.MentorIds.Contains(UserId)) + return BadRequest("Добавлять автоматизированные решения могут только зарегистрированные на курс агенты"); - [HttpPost("giveUp/{taskId}")] - [Authorize(Roles = Roles.StudentRole)] - public async Task GiveUp(long taskId) + var tasks = course.Homeworks.SelectMany(t => t.Tasks); + var task = model.TaskIdType switch { - var course = await _coursesServiceClient.GetCourseByTask(taskId); - if (course == null) return NotFound(); - if (course.CourseMates.All(t => t.StudentId != UserId)) - return BadRequest($"Студент с id {UserId} не записан на курс"); - - await _solutionsClient.PostEmptySolutionWithRate(taskId, new SolutionViewModel() - { - StudentId = UserId, - Comment = "[Студент отказался от выполнения задачи]", - Rating = 0 - }); - return Ok(); - } - - [HttpPost("rateSolution/{solutionId}")] - [Authorize(Roles = Roles.LecturerOrExpertRole)] - public async Task RateSolution(long solutionId, - RateSolutionModel rateSolutionModel) + TaskIdType.Id when long.TryParse(model.TaskId, out var taskId) => tasks.FirstOrDefault(x => x.Id == taskId), + TaskIdType.Title => tasks.FirstOrDefault(x => x.Title == model.TaskId), + _ => null + }; + if (task is null) return BadRequest($"Задача с {model.TaskIdType} = {model.TaskId} не найдена"); + + var students = + await AuthServiceClient.GetAccountsData(course.AcceptedStudents.Select(x => x.StudentId).ToArray()); + var studentCandidates = model.StudentIdType switch { - await _solutionsClient.RateSolution(solutionId, rateSolutionModel); - return Ok(); - } - - [HttpGet("actuality/{solutionId}")] - [ProducesResponseType(typeof(SolutionActualityDto), (int)HttpStatusCode.OK)] - public async Task GetSolutionActuality(long solutionId) + StudentIdType.Id => students.FirstOrDefault(x => x.UserId == model.StudentId) is { } s + ? [s] + : [], + StudentIdType.FullName => students + .Where(x => + model.StudentId.Contains(x.Name.Trim()) && + model.StudentId.Contains(x.Surname.Trim()) && + (string.IsNullOrEmpty(x.MiddleName) || model.StudentId.Contains(x.MiddleName.Trim()))) + .ToArray(), + StudentIdType.GitHub => students.Where(x => x.GithubId == model.StudentId).ToArray(), + _ => [] + }; + + switch (studentCandidates.Length) { - var result = await _solutionsClient.GetSolutionActuality(solutionId); - return Ok(result); + case 0: + return BadRequest($"Студент с {model.StudentIdType} = {model.StudentId} не записан на курс"); + case > 1: + return BadRequest( + $"Найдено несколько студентов с {model.StudentIdType} = {model.StudentId}. Измените StudentIdType или StudentId, чтобы уточнить запрос"); } - [HttpPost("markSolutionFinal/{solutionId}")] - [Authorize(Roles = Roles.LecturerRole)] - public async Task MarkSolution(long solutionId) - { - await _solutionsClient.MarkSolution(solutionId); - return Ok(); - } + var student = studentCandidates.First(); + var solutions = await _solutionsClient.GetUserSolutions(task.Id, student.UserId); + if (solutions.OrderBy(x => x.PublicationDate).LastOrDefault()?.State == SolutionState.Posted) + return Ok( + "Последнее решение студента по задаче ещё не проверено. Все хорошо, но новое решение не будет добавлено"); - [HttpDelete("delete/{solutionId}")] - [Authorize(Roles = Roles.LecturerRole)] - public async Task DeleteSolution(long solutionId) + await _solutionsClient.PostSolution(task.Id, new HwProj.Models.SolutionsService.PostSolutionModel { - await _solutionsClient.DeleteSolution(solutionId); - return Ok(); - } + GithubUrl = model.GithubUrl, + Comment = model.Comment, + StudentId = student.UserId + }); - [HttpGet("unratedSolutions")] - [Authorize(Roles = Roles.LecturerOrExpertRole)] - public async Task GetUnratedSolutions(long? taskId) + return Ok("Решение успешно добавлено в очередь на проверку!"); + } + + [HttpPost("rateEmptySolution/{taskId}")] + [Authorize(Roles = Roles.LecturerOrExpertRole)] + public async Task PostEmptySolutionWithRate(long taskId, SolutionViewModel solution) + { + var course = await _coursesServiceClient.GetCourseByTask(taskId); + if (course == null || !course.MentorIds.Contains(UserId)) return Forbid(); + if (course.CourseMates.All(t => t.StudentId != solution.StudentId)) + return BadRequest($"Студент с id {solution.StudentId} не записан на курс"); + + solution.Comment = "[Решение было сдано вне сервиса]"; + await _solutionsClient.PostEmptySolutionWithRate(taskId, solution); + return Ok(); + } + + [HttpPost("giveUp/{taskId}")] + [Authorize(Roles = Roles.StudentRole)] + public async Task GiveUp(long taskId) + { + var course = await _coursesServiceClient.GetCourseByTask(taskId); + if (course == null) return NotFound(); + if (course.CourseMates.All(t => t.StudentId != UserId)) + return BadRequest($"Студент с id {UserId} не записан на курс"); + + await _solutionsClient.PostEmptySolutionWithRate(taskId, new SolutionViewModel { - var mentorCourses = await _coursesServiceClient.GetAllUserCourses(); - var tasks = FilterTasks(mentorCourses, taskId).ToDictionary(t => t.taskId, t => t.data); + StudentId = UserId, + Comment = "[Студент отказался от выполнения задачи]", + Rating = 0 + }); + return Ok(); + } - var studentsAndTasks = new Dictionary studentIds, List taskIds)>(); - foreach (var value in tasks.Values) - { - studentsAndTasks.TryAdd( - value.course.Id, ( - value.course.AcceptedStudents.Select(ast => ast.StudentId).ToList(), - new List())); - studentsAndTasks[value.course.Id].taskIds.Add(value.task.Id); - } + [HttpPost("rateSolution/{solutionId}")] + [Authorize(Roles = Roles.LecturerOrExpertRole)] + public async Task RateSolution(long solutionId, + RateSolutionModel rateSolutionModel) + { + await _solutionsClient.RateSolution(solutionId, rateSolutionModel); + return Ok(); + } - var solutions = await GetAllUnratedSolutionsForTasks(studentsAndTasks); + [HttpGet("actuality/{solutionId}")] + [ProducesResponseType(typeof(SolutionActualityDto), (int)HttpStatusCode.OK)] + public async Task GetSolutionActuality(long solutionId) + { + var result = await _solutionsClient.GetSolutionActuality(solutionId); + return Ok(result); + } - var studentIds = solutions.Select(t => t.StudentId).Distinct().ToArray(); - var accountsData = await AuthServiceClient.GetAccountsData(studentIds); + [HttpPost("markSolutionFinal/{solutionId}")] + [Authorize(Roles = Roles.LecturerRole)] + public async Task MarkSolution(long solutionId) + { + await _solutionsClient.MarkSolution(solutionId); + return Ok(); + } - var unratedSolutions = solutions - .Join(accountsData, s => s.StudentId, s => s.UserId, (solution, account) => - { - var (course, homeworkTitle, task) = tasks[solution.TaskId]; - return new SolutionPreviewView - { - SolutionId = solution.SolutionId, - Student = account, - CourseTitle = $"{course.Name} / {course.GroupName}", - CourseId = course.Id, - HomeworkTitle = homeworkTitle, - TaskTitle = task.Title, - TaskId = task.Id, - PublicationDate = solution.PublicationDate, - IsFirstTry = solution.IsFirstTry, - GroupId = solution.GroupId, - SentAfterDeadline = solution.IsFirstTry && task.DeadlineDate != null && - solution.PublicationDate > task.DeadlineDate, - IsCourseCompleted = course.IsCompleted - }; - }) - .ToArray(); - - return new UnratedSolutionPreviews - { - UnratedSolutions = unratedSolutions, - }; - } + [HttpDelete("delete/{solutionId}")] + [Authorize(Roles = Roles.LecturerRole)] + public async Task DeleteSolution(long solutionId) + { + await _solutionsClient.DeleteSolution(solutionId); + return Ok(); + } + + [HttpGet("unratedSolutions")] + [Authorize(Roles = Roles.LecturerOrExpertRole)] + public async Task GetUnratedSolutions(long? taskId) + { + var mentorCourses = await _coursesServiceClient.GetAllUserCourses(); + var tasks = FilterTasks(mentorCourses, taskId).ToDictionary(t => t.taskId, t => t.data); - [Authorize] - [HttpGet("solutionAchievement")] - [ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)] - public async Task GetSolutionAchievement(long taskId, long solutionId) + var studentsAndTasks = new Dictionary studentIds, List taskIds)>(); + foreach (var value in tasks.Values) { - var course = await _coursesServiceClient.GetCourseByTask(taskId); - if (course is null) return BadRequest(); - - var isMentor = course.MentorIds.Contains(UserId); - if (!isMentor && - course.AcceptedStudents.FirstOrDefault(t => t.StudentId == UserId) == null) - return BadRequest($"Студента или преподавателя с id {UserId} не существует"); - - var solutions = await _solutionsClient.GetTaskSolutionStatistics(course.Id, taskId); - var lastRatedSolutions = solutions - .Select(t => t.Solutions.LastOrDefault(x => x.State != SolutionState.Posted)) - .Where(t => t != null) - .ToArray(); - - var solution = lastRatedSolutions.FirstOrDefault(t => t!.Id == solutionId && - (isMentor || t.StudentId == UserId)); - if (solution == null) return NotFound(); - - if (lastRatedSolutions.Any(x => x!.GroupId != null)) - lastRatedSolutions = lastRatedSolutions.DistinctBy(t => t!.Id).ToArray(); - - var betterThanCount = lastRatedSolutions.Count(t => solution.Rating > t!.Rating); - if (betterThanCount == 0) return Ok(lastRatedSolutions.Length == 1 ? 100 : 0); - return Ok(betterThanCount * 100 / (lastRatedSolutions.Length - 1)); + studentsAndTasks.TryAdd( + value.course.Id, ( + value.course.AcceptedStudents.Select(ast => ast.StudentId).ToList(), + new List())); + studentsAndTasks[value.course.Id].taskIds.Add(value.task.Id); } - private async Task GetAllUnratedSolutionsForTasks( - Dictionary studentIds, List taskIds)> tasksAndStudents) - { - var solutions = new List>(); + var solutions = await GetAllUnratedSolutionsForTasks(studentsAndTasks); - foreach (var value in tasksAndStudents.Values) + var studentIds = solutions.Select(t => t.StudentId).Distinct().ToArray(); + var accountsData = await AuthServiceClient.GetAccountsData(studentIds); + + var unratedSolutions = solutions + .Join(accountsData, s => s.StudentId, s => s.UserId, (solution, account) => { - solutions.Add( - _solutionsClient.GetAllUnratedSolutionsForTasks( - new GetTasksSolutionsModel - { - TaskIds = value.taskIds.ToArray(), - StudentIds = value.studentIds.ToArray() - } - ) - ); - } + var (course, homeworkTitle, task) = tasks[solution.TaskId]; + return new SolutionPreviewView + { + SolutionId = solution.SolutionId, + Student = account, + CourseTitle = $"{course.Name} / {course.GroupName}", + CourseId = course.Id, + HomeworkTitle = homeworkTitle, + TaskTitle = task.Title, + TaskId = task.Id, + PublicationDate = solution.PublicationDate, + IsFirstTry = solution.IsFirstTry, + GroupId = solution.GroupId, + SentAfterDeadline = solution.IsFirstTry && task.DeadlineDate != null && + solution.PublicationDate > task.DeadlineDate, + IsCourseCompleted = course.IsCompleted, + IsTest = task.Tags.Contains(HomeworkTags.Test) + }; + }) + .ToArray(); - var allSolutions = await Task.WhenAll(solutions); - return allSolutions.SelectMany(s => s).OrderBy(s => s.PublicationDate).ToArray(); - } + return new UnratedSolutionPreviews + { + UnratedSolutions = unratedSolutions + }; + } - private static IEnumerable<(long taskId, - (CourseDTO course, string homeworkTitle, HomeworkTaskViewModel task) data)> - FilterTasks(CourseDTO[] courses, long? taskId) + [Authorize] + [HttpGet("solutionAchievement")] + [ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)] + public async Task GetSolutionAchievement(long taskId, long solutionId) + { + var course = await _coursesServiceClient.GetCourseByTask(taskId); + if (course is null) return BadRequest(); + + var isMentor = course.MentorIds.Contains(UserId); + if (!isMentor && + course.AcceptedStudents.FirstOrDefault(t => t.StudentId == UserId) == null) + return BadRequest($"Студента или преподавателя с id {UserId} не существует"); + + var solutions = await _solutionsClient.GetTaskSolutionStatistics(course.Id, taskId); + var lastRatedSolutions = solutions + .Select(t => t.Solutions.LastOrDefault(x => x.State != SolutionState.Posted)) + .Where(t => t != null) + .ToArray(); + + var solution = lastRatedSolutions.FirstOrDefault(t => t!.Id == solutionId && + (isMentor || t.StudentId == UserId)); + if (solution == null) return NotFound(); + + if (lastRatedSolutions.Any(x => x!.GroupId != null)) + lastRatedSolutions = lastRatedSolutions.DistinctBy(t => t!.Id).ToArray(); + + var betterThanCount = lastRatedSolutions.Count(t => solution.Rating > t!.Rating); + if (betterThanCount == 0) return Ok(lastRatedSolutions.Length == 1 ? 100 : 0); + return Ok(betterThanCount * 100 / (lastRatedSolutions.Length - 1)); + } + + private async Task GetAllUnratedSolutionsForTasks( + Dictionary studentIds, List taskIds)> tasksAndStudents) + { + var solutions = new List>(); + + foreach (var value in tasksAndStudents.Values) + solutions.Add( + _solutionsClient.GetAllUnratedSolutionsForTasks( + new GetTasksSolutionsModel + { + TaskIds = value.taskIds.ToArray(), + StudentIds = value.studentIds.ToArray() + } + ) + ); + + var allSolutions = await Task.WhenAll(solutions); + return allSolutions.SelectMany(s => s).OrderBy(s => s.PublicationDate).ToArray(); + } + + private static IEnumerable<(long taskId, + (CourseDTO course, string homeworkTitle, HomeworkTaskViewModel task) data)> + FilterTasks(CourseDTO[] courses, long? taskId) + { + foreach (var course in courses) + foreach (var homework in course.Homeworks) + foreach (var task in homework.Tasks) { - foreach (var course in courses) - foreach (var homework in course.Homeworks) - foreach (var task in homework.Tasks) + if (taskId is { } id && task.Id == id) { - if (taskId is { } id && task.Id == id) - { - yield return (task.Id, (course, homework.Title, task)); - yield break; - } - - if (!taskId.HasValue) - yield return (task.Id, (course, homework.Title, task)); + yield return (task.Id, (course, homework.Title, task)); + yield break; } - } - private static (string id, string tasks) GetGroupingKey(HomeworkViewModel homework) - { - var isTest = homework.Tags.Contains(HomeworkTags.Test); - var groupingTag = homework.Tags.Except(HomeworkTags.DefaultTags).FirstOrDefault(); - return isTest && groupingTag != null - ? (groupingTag, string.Join(";", homework.Tasks.Select(t => t.MaxRating))) - : (homework.Id.ToString(), ""); + if (!taskId.HasValue) + yield return (task.Id, (course, homework.Title, task)); } } + + private static (string id, string tasks) GetGroupingKey(HomeworkViewModel homework) + { + var isTest = homework.Tags.Contains(HomeworkTags.Test); + var groupingTag = homework.Tags.Except(HomeworkTags.DefaultTags).FirstOrDefault(); + return isTest && groupingTag != null + ? (groupingTag, string.Join(";", homework.Tasks.Select(t => t.MaxRating))) + : (homework.Id.ToString(), ""); + } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/StatisticsController.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/StatisticsController.cs index 0f0617a02..dfd6c567f 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/StatisticsController.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/StatisticsController.cs @@ -14,143 +14,142 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace HwProj.APIGateway.API.Controllers +namespace HwProj.APIGateway.API.Controllers; + +[Route("api/[controller]")] +[ApiController] +public class StatisticsController : AggregationController { - [Route("api/[controller]")] - [ApiController] - public class StatisticsController : AggregationController + private readonly ICoursesServiceClient _coursesClient; + private readonly ISolutionsServiceClient _solutionClient; + + public StatisticsController(ISolutionsServiceClient solutionClient, IAuthServiceClient authServiceClient, + ICoursesServiceClient coursesServiceClient) : + base(authServiceClient) { - private readonly ISolutionsServiceClient _solutionClient; - private readonly ICoursesServiceClient _coursesClient; + _solutionClient = solutionClient; + _coursesClient = coursesServiceClient; + } - public StatisticsController(ISolutionsServiceClient solutionClient, IAuthServiceClient authServiceClient, - ICoursesServiceClient coursesServiceClient) : - base(authServiceClient) - { - _solutionClient = solutionClient; - _coursesClient = coursesServiceClient; - } - - [HttpGet("{courseId}/lecturers")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(StatisticsLecturersModel[]), (int)HttpStatusCode.OK)] - public async Task GetLecturersStatistics(long courseId) + [HttpGet("{courseId}/lecturers")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(StatisticsLecturersModel[]), (int)HttpStatusCode.OK)] + public async Task GetLecturersStatistics(long courseId) + { + var statistics = await _solutionClient.GetLecturersStatistics(courseId); + if (statistics == null) + return NotFound(); + + var lecturers = await AuthServiceClient.GetAccountsData(statistics.Select(s => s.LecturerId).ToArray()); + + var result = statistics.Zip(lecturers, (stat, lecturer) => new StatisticsLecturersModel { - var statistics = await _solutionClient.GetLecturersStatistics(courseId); - if (statistics == null) - return NotFound(); + Lecturer = lecturer, + NumberOfCheckedSolutions = stat.NumberOfCheckedSolutions, + NumberOfCheckedUniqueSolutions = stat.NumberOfCheckedUniqueSolutions + }).ToArray(); - var lecturers = await AuthServiceClient.GetAccountsData(statistics.Select(s => s.LecturerId).ToArray()); + return Ok(result); + } - var result = statistics.Zip(lecturers, (stat, lecturer) => new StatisticsLecturersModel - { - Lecturer = lecturer, - NumberOfCheckedSolutions = stat.NumberOfCheckedSolutions, - NumberOfCheckedUniqueSolutions = stat.NumberOfCheckedUniqueSolutions - }).ToArray(); + [HttpGet("{courseId}")] + [ProducesResponseType(typeof(StatisticsCourseMatesModel[]), (int)HttpStatusCode.OK)] + public async Task GetCourseStatistics(long courseId) + { + var statistics = await _solutionClient.GetCourseStatistics(courseId, UserId); + if (statistics == null) return Forbid(); - return Ok(result); - } + var studentIds = statistics.Select(t => t.StudentId).ToArray(); + var getStudentsTask = AuthServiceClient.GetAccountsData(studentIds); - [HttpGet("{courseId}")] - [ProducesResponseType(typeof(StatisticsCourseMatesModel[]), (int)HttpStatusCode.OK)] - public async Task GetCourseStatistics(long courseId) - { - var statistics = await _solutionClient.GetCourseStatistics(courseId, UserId); - if (statistics == null) return Forbid(); - - var studentIds = statistics.Select(t => t.StudentId).ToArray(); - var getStudentsTask = AuthServiceClient.GetAccountsData(studentIds); - - // Получаем пары <студент, закрепленные преподаватели (те, которые его явно в фильтре выбрали)> - var mentorsToStudents = await _coursesClient.GetMentorsToAssignedStudents(courseId); - var studentsToMentors = await GetStudentsToMentorsDictionary(mentorsToStudents); - - var result = statistics.Zip( - await getStudentsTask, - (stats, student) => + // Получаем пары <студент, закрепленные преподаватели (те, которые его явно в фильтре выбрали)> + var mentorsToStudents = await _coursesClient.GetMentorsToAssignedStudents(courseId); + var studentsToMentors = await GetStudentsToMentorsDictionary(mentorsToStudents); + + var result = statistics.Zip( + await getStudentsTask, + (stats, student) => + { + studentsToMentors.TryGetValue(student.UserId, out var reviewers); + return new StatisticsCourseMatesModel { - studentsToMentors.TryGetValue(student.UserId, out var reviewers); - return new StatisticsCourseMatesModel() - { - Id = student.UserId, - Name = student.Name, - Surname = student.Surname, - Reviewers = reviewers ?? Array.Empty(), - Homeworks = stats.Homeworks - }; - }).OrderBy(t => t.Surname).ThenBy(t => t.Name); - - return Ok(result); - } - - [HttpGet("{courseId}/charts")] - [ProducesResponseType(typeof(AdvancedCourseStatisticsViewModel), (int)HttpStatusCode.OK)] - public async Task GetChartStatistics(long courseId) - { - var course = await _coursesClient.GetCourseById(courseId); - if (course == null) - return Forbid(); + Id = student.UserId, + Name = student.Name, + Surname = student.Surname, + Reviewers = reviewers ?? Array.Empty(), + Homeworks = stats.Homeworks + }; + }).OrderBy(t => t.Surname).ThenBy(t => t.Name); - var statistics = await _solutionClient.GetCourseStatistics(courseId, UserId); - var studentIds = statistics.Select(t => t.StudentId).ToArray(); - var studentsData = await AuthServiceClient.GetAccountsData(studentIds); + return Ok(result); + } - var students = statistics.Zip(studentsData, - (stats, student) => new StatisticsCourseMatesModel + [HttpGet("{courseId}/charts")] + [ProducesResponseType(typeof(AdvancedCourseStatisticsViewModel), (int)HttpStatusCode.OK)] + public async Task GetChartStatistics(long courseId) + { + var course = await _coursesClient.GetCourseById(courseId); + if (course == null) + return Forbid(); + + var statistics = await _solutionClient.GetCourseStatistics(courseId, UserId); + var studentIds = statistics.Select(t => t.StudentId).ToArray(); + var studentsData = await AuthServiceClient.GetAccountsData(studentIds); + + var students = statistics.Zip(studentsData, + (stats, student) => new StatisticsCourseMatesModel { Id = student.UserId, Name = student.Name, Surname = student.Surname, Homeworks = stats.Homeworks }).OrderBy(t => t.Surname).ThenBy(t => t.Name); - - var statisticsMeasure = await _solutionClient.GetBenchmarkStatistics(courseId); - var result = new AdvancedCourseStatisticsViewModel - { - Course = new CoursePreview - { - Id = course.Id, - Name = course.Name, - GroupName = course.GroupName, - }, - StudentStatistics = students.ToArray(), - Homeworks = course.Homeworks, - AverageStudentSolutions = statisticsMeasure.AverageStudentSolutions, - BestStudentSolutions = statisticsMeasure.BestStudentSolutions - }; - - return Ok(result); - } - - private async Task> GetStudentsToMentorsDictionary( - MentorToAssignedStudentsDTO[] mentorsToStudents) + var statisticsMeasure = await _solutionClient.GetBenchmarkStatistics(courseId); + + var result = new AdvancedCourseStatisticsViewModel { - var mentorsIds = mentorsToStudents.Select(mts => mts.MentorId).ToArray(); - var mentorsAccountData = await AuthServiceClient.GetAccountsData(mentorsIds); - var mentorIdToAccountData = mentorsAccountData - .ToDictionary( - accountData => accountData.UserId, - accountData => accountData - ); - - return mentorsToStudents - .SelectMany(m => - m.SelectedStudentsIds.Select(studentId => - new - { - StudentId = studentId, - Reviewer = mentorIdToAccountData[m.MentorId] - }) - ) - .GroupBy(sr => sr.StudentId) - .ToDictionary( - groups => groups.Key, - groups => groups.Select(sr => sr.Reviewer) - .Distinct() - .ToArray() - ); - } + Course = new CoursePreview + { + Id = course.Id, + Name = course.Name, + GroupName = course.GroupName + }, + StudentStatistics = students.ToArray(), + Homeworks = course.Homeworks, + AverageStudentSolutions = statisticsMeasure.AverageStudentSolutions, + BestStudentSolutions = statisticsMeasure.BestStudentSolutions + }; + + return Ok(result); + } + + private async Task> GetStudentsToMentorsDictionary( + MentorToAssignedStudentsDTO[] mentorsToStudents) + { + var mentorsIds = mentorsToStudents.Select(mts => mts.MentorId).ToArray(); + var mentorsAccountData = await AuthServiceClient.GetAccountsData(mentorsIds); + var mentorIdToAccountData = mentorsAccountData + .ToDictionary( + accountData => accountData.UserId, + accountData => accountData + ); + + return mentorsToStudents + .SelectMany(m => + m.SelectedStudentsIds.Select(studentId => + new + { + StudentId = studentId, + Reviewer = mentorIdToAccountData[m.MentorId] + }) + ) + .GroupBy(sr => sr.StudentId) + .ToDictionary( + groups => groups.Key, + groups => groups.Select(sr => sr.Reviewer) + .Distinct() + .ToArray() + ); } -} \ No newline at end of file +} diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/SystemController.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/SystemController.cs index 61fb17326..233bd6ed4 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/SystemController.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/SystemController.cs @@ -1,65 +1,74 @@ using System.Threading.Tasks; using HwProj.APIGateway.API.Models; using HwProj.AuthService.Client; +using HwProj.ContentService.Client; using HwProj.CoursesService.Client; using HwProj.NotificationsService.Client; using HwProj.SolutionsService.Client; using Microsoft.AspNetCore.Mvc; -namespace HwProj.APIGateway.API.Controllers +namespace HwProj.APIGateway.API.Controllers; + +[Route("api/[controller]")] +[ApiController] +public class SystemController : AggregationController { - [Route("api/[controller]")] - [ApiController] - public class SystemController : AggregationController - { - private readonly ICoursesServiceClient _coursesServiceClient; - private readonly INotificationsServiceClient _notificationsServiceClient; - private readonly ISolutionsServiceClient _solutionsServiceClient; + private readonly IContentServiceClient _contentServiceClient; + private readonly ICoursesServiceClient _coursesServiceClient; + private readonly INotificationsServiceClient _notificationsServiceClient; + private readonly ISolutionsServiceClient _solutionsServiceClient; - public SystemController( - IAuthServiceClient authServiceClient, - ICoursesServiceClient coursesServiceClient, - INotificationsServiceClient notificationsServiceClient, - ISolutionsServiceClient solutionsServiceClient) : base(authServiceClient) - { - _coursesServiceClient = coursesServiceClient; - _notificationsServiceClient = notificationsServiceClient; - _solutionsServiceClient = solutionsServiceClient; - } + public SystemController( + IAuthServiceClient authServiceClient, + ICoursesServiceClient coursesServiceClient, + INotificationsServiceClient notificationsServiceClient, + ISolutionsServiceClient solutionsServiceClient, + IContentServiceClient contentServiceClient) : base(authServiceClient) + { + _coursesServiceClient = coursesServiceClient; + _notificationsServiceClient = notificationsServiceClient; + _solutionsServiceClient = solutionsServiceClient; + _contentServiceClient = contentServiceClient; + } - [HttpGet("status")] - public async Task Status() - { - var authPing = AuthServiceClient.Ping(); - var coursesPing = _coursesServiceClient.Ping(); - var notificationsPing = _notificationsServiceClient.Ping(); - var solutionsPing = _solutionsServiceClient.Ping(); + [HttpGet("status")] + public async Task Status() + { + var authPing = AuthServiceClient.Ping(); + var coursesPing = _coursesServiceClient.Ping(); + var notificationsPing = _notificationsServiceClient.Ping(); + var solutionsPing = _solutionsServiceClient.Ping(); + var filesPing = _contentServiceClient.Ping(); - await Task.WhenAll(authPing, coursesPing, notificationsPing, solutionsPing); + await Task.WhenAll(authPing, coursesPing, notificationsPing, solutionsPing); - return new[] + return new[] + { + new SystemInfo + { + Service = "Auth Service", + IsAvailable = authPing.Result + }, + new SystemInfo + { + Service = "Courses Service", + IsAvailable = coursesPing.Result + }, + new SystemInfo + { + Service = "Notifications Service", + IsAvailable = notificationsPing.Result + }, + new SystemInfo + { + Service = "Solutions Service", + IsAvailable = solutionsPing.Result + }, + new SystemInfo { - new SystemInfo - { - Service = "Auth Service", - IsAvailable = authPing.Result - }, - new SystemInfo - { - Service = "Courses Service", - IsAvailable = coursesPing.Result - }, - new SystemInfo - { - Service = "Notifications Service", - IsAvailable = notificationsPing.Result - }, - new SystemInfo - { - Service = "Solutions Service", - IsAvailable = solutionsPing.Result - }, - }; - } + Service = "Content Service", + IsAvailable = filesPing.Result + } + }; } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/TasksController.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/TasksController.cs index 938b86d4b..deabf55cd 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/TasksController.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/TasksController.cs @@ -4,95 +4,95 @@ using HwProj.Models.CoursesService.ViewModels; using HwProj.Models.Result; using HwProj.Models.Roles; -using HwProj.Utils.Authorization; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace HwProj.APIGateway.API.Controllers +namespace HwProj.APIGateway.API.Controllers; + +[Route("api/[controller]")] +[ApiController] +public class TasksController(ICoursesServiceClient coursesClient) : ControllerBase { - [Route("api/[controller]")] - [ApiController] - public class TasksController : ControllerBase + [HttpGet("get/{taskId}")] + [Authorize] + [ProducesResponseType(typeof(HomeworkTaskViewModel), (int)HttpStatusCode.OK)] + public async Task GetTask(long taskId, [FromQuery] bool? withCriteria) { - private readonly ICoursesServiceClient _coursesClient; - - public TasksController(ICoursesServiceClient coursesClient) - { - _coursesClient = coursesClient; - } + var result = await coursesClient.GetTask(taskId, withCriteria ?? false); + return result == null + ? NotFound() + : Ok(result); + } - [HttpGet("get/{taskId}")] - [Authorize] - [ProducesResponseType(typeof(HomeworkTaskViewModel), (int)HttpStatusCode.OK)] - public async Task GetTask(long taskId) - { - var result = await _coursesClient.GetTask(taskId); - return result == null - ? NotFound() as IActionResult - : Ok(result); - } + [HttpGet("getForEditing/{taskId}")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(HomeworkTaskForEditingViewModel), (int)HttpStatusCode.OK)] + public async Task GetForEditingTask(long taskId) + { + var result = await coursesClient.GetForEditingTask(taskId); + return result == null + ? NotFound() + : Ok(result); + } - [HttpGet("getForEditing/{taskId}")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(HomeworkTaskForEditingViewModel), (int)HttpStatusCode.OK)] - public async Task GetForEditingTask(long taskId) - { - var result = await _coursesClient.GetForEditingTask(taskId); - return result == null - ? NotFound() as IActionResult - : Ok(result); - } + [HttpPost("add/{homeworkId}")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] + public async Task AddTask(long homeworkId, PostTaskViewModel taskViewModel) + { + var result = await coursesClient.AddTask(homeworkId, taskViewModel); + return result.Succeeded + ? Ok(result) + : BadRequest(result); + } - [HttpPost("add/{homeworkId}")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(long), (int)HttpStatusCode.OK)] - public async Task AddTask(long homeworkId, CreateTaskViewModel taskViewModel) - { - var result = await _coursesClient.AddTask(homeworkId, taskViewModel); - return result.Succeeded - ? Ok(result.Value) as IActionResult - : BadRequest(result.Errors); - } + [HttpDelete("delete/{taskId}")] + [Authorize(Roles = Roles.LecturerRole)] + public async Task DeleteTask(long taskId) + { + await coursesClient.DeleteTask(taskId); + return Ok(); + } - [HttpDelete("delete/{taskId}")] - [Authorize(Roles = Roles.LecturerRole)] - public async Task DeleteTask(long taskId) - { - await _coursesClient.DeleteTask(taskId); - return Ok(); - } + [HttpPut("update/{taskId}")] + [Authorize(Roles = Roles.LecturerRole)] + [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] + public async Task UpdateTask(long taskId, PostTaskViewModel taskViewModel) + { + var result = await coursesClient.UpdateTask(taskId, taskViewModel); + return Ok(result); + } - [HttpPut("update/{taskId}")] - [Authorize(Roles = Roles.LecturerRole)] - [ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)] - public async Task UpdateTask(long taskId, CreateTaskViewModel taskViewModel) - { - var result = await _coursesClient.UpdateTask(taskId, taskViewModel); - return Ok(result); - } + [HttpPost("addQuestion")] + [Authorize(Roles = Roles.StudentRole)] + public async Task AddQuestionForTask(AddTaskQuestionDto question) + { + await coursesClient.AddQuestionForTask(question); + return Ok(); + } - [HttpPost("addQuestion")] - [Authorize(Roles = Roles.StudentRole)] - public async Task AddQuestionForTask(AddTaskQuestionDto question) - { - await _coursesClient.AddQuestionForTask(question); - return Ok(); - } + [HttpGet("questions/{taskId}")] + [ProducesResponseType(typeof(GetTaskQuestionDto[]), (int)HttpStatusCode.OK)] + public async Task GetQuestionsForTask(long taskId) + { + var result = await coursesClient.GetQuestionsForTask(taskId); + return Ok(result); + } - [HttpGet("questions/{taskId}")] - [ProducesResponseType(typeof(GetTaskQuestionDto[]), (int)HttpStatusCode.OK)] - public async Task GetQuestionsForTask(long taskId) - { - var result = await _coursesClient.GetQuestionsForTask(taskId); - return Ok(result); - } + [HttpPost("addAnswer")] + [Authorize(Roles = Roles.LecturerOrExpertRole)] + public async Task AddAnswerForQuestion(AddAnswerForQuestionDto answer) + { + await coursesClient.AddAnswerForQuestion(answer); + return Ok(); + } - [HttpPost("addAnswer")] - [Authorize(Roles = Roles.LecturerOrExpertRole)] - public async Task AddAnswerForQuestion(AddAnswerForQuestionDto answer) - { - await _coursesClient.AddAnswerForQuestion(answer); - return Ok(); - } + [HttpGet("openQuestions")] + [Authorize(Roles = Roles.LecturerOrExpertRole)] + [ProducesResponseType(typeof(QuestionsSummary[]), (int)HttpStatusCode.OK)] + public async Task GetOpenQuestions() + { + var result = await coursesClient.GetOpenQuestions(); + return Ok(result); } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Dockerfile b/HwProj.APIGateway/HwProj.APIGateway.API/Dockerfile index be8d9281e..dc0142c63 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Dockerfile +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY ["Directory.Build.props", "Directory.Build.props"] @@ -16,13 +16,12 @@ COPY ["HwProj.SolutionsService/HwProj.SolutionsService.Client/", "HwProj.Solutio COPY ["HwProj.Common/HwProj.Exceptions/", "HwProj.Common/HwProj.Exceptions/"] COPY ["HwProj.ContentService/HwProj.ContentService.Client/", "HwProj.ContentService/HwProj.ContentService.Client/"] COPY ["HwProj.StudentInfo/IStudentsInfo/", "HwProj.StudentInfo/IStudentsInfo/"] -COPY ["HwProj.StudentInfo/StudentsInfo.Tests/", "HwProj.StudentInfo/StudentsInfo.Tests/"] COPY ["HwProj.StudentInfo/StudentsInfo/", "HwProj.StudentInfo/StudentsInfo/"] WORKDIR "/src/HwProj.APIGateway/HwProj.APIGateway.API" RUN dotnet publish "HwProj.APIGateway.API.csproj" -c Release -o /app/publish -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim AS final +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final WORKDIR /app COPY --from=build /app/publish . diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/ExceptionFilters/ForbiddenExceptionFilter.cs b/HwProj.APIGateway/HwProj.APIGateway.API/ExceptionFilters/ForbiddenExceptionFilter.cs index 677cbaa64..a6947df45 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/ExceptionFilters/ForbiddenExceptionFilter.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/ExceptionFilters/ForbiddenExceptionFilter.cs @@ -1,19 +1,17 @@ -using Microsoft.AspNetCore.Mvc.Filters; using System; using HwProj.Exceptions; +using Microsoft.AspNetCore.Mvc.Filters; +namespace HwProj.APIGateway.API.ExceptionFilters; -namespace HwProj.APIGateway.API.ExceptionFilters +public class ForbiddenExceptionFilter : Attribute, IExceptionFilter { - public class ForbiddenExceptionFilter : Attribute, IExceptionFilter + public void OnException(ExceptionContext context) { - public void OnException(ExceptionContext context) + if (context.Exception is ForbiddenException) { - if (context.Exception is ForbiddenException) - { - context.ExceptionHandled = true; - context.HttpContext.Response.StatusCode = 403; - } + context.ExceptionHandled = true; + context.HttpContext.Response.StatusCode = 403; } } -} \ No newline at end of file +} diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Filters/CourseMentorOnlyAttribute.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Filters/CourseMentorOnlyAttribute.cs index 0b2871182..22eeb698d 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Filters/CourseMentorOnlyAttribute.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Filters/CourseMentorOnlyAttribute.cs @@ -1,67 +1,75 @@ using System.Linq; using System.Threading.Tasks; using HwProj.CoursesService.Client; +using HwProj.Models.ContentService.DTO; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; -namespace HwProj.APIGateway.API.Filters +namespace HwProj.APIGateway.API.Filters; + +public class CourseMentorOnlyAttribute : ActionFilterAttribute { - public class CourseMentorOnlyAttribute : ActionFilterAttribute + private readonly ICoursesServiceClient _coursesServiceClient; + + public CourseMentorOnlyAttribute(ICoursesServiceClient coursesServiceClient) { - private readonly ICoursesServiceClient _coursesServiceClient; + _coursesServiceClient = coursesServiceClient; + } - public CourseMentorOnlyAttribute(ICoursesServiceClient coursesServiceClient) + public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + var userId = context.HttpContext.User.Claims + .FirstOrDefault(claim => claim.Type.ToString() == "_id")?.Value; + if (userId == null) { - _coursesServiceClient = coursesServiceClient; + context.Result = new ContentResult + { + StatusCode = StatusCodes.Status403Forbidden, + Content = "В запросе не передан идентификатор пользователя", + ContentType = "application/json" + }; + return; } - public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) - { - var userId = context.HttpContext.User.Claims - .FirstOrDefault(claim => claim.Type.ToString() == "_id")?.Value; - if (userId == null) - { - context.Result = new ContentResult - { - StatusCode = StatusCodes.Status403Forbidden, - Content = "В запросе не передан идентификатор пользователя", - ContentType = "application/json" - }; - return; - } - - string[]? mentorIds = null; - - var courseId = GetValueFromRequest(context.HttpContext.Request, "courseId"); - if (courseId != null && long.TryParse(courseId, out var id)) - { - mentorIds = await _coursesServiceClient.GetCourseLecturersIds(id); - } + string[]? mentorIds = null; + long courseId = -1; - if (mentorIds == null || !mentorIds.Contains(userId)) - { - context.Result = new ContentResult - { - StatusCode = StatusCodes.Status403Forbidden, - Content = "Недостаточно прав для работы с файлами: Вы не являетесь ментором на курсе", - ContentType = "application/json" - }; - return; - } + // Для метода Process (параметр: processFilesDto) + if (context.ActionArguments.TryGetValue("processFilesDto", out var processFilesDto) && + processFilesDto is ProcessFilesDTO dto) + courseId = dto.FilesScope.CourseId; - await next.Invoke(); - } - - private static string? GetValueFromRequest(HttpRequest request, string key) + // Для метода GetStatuses (параметр: filesScope) + else if (context.ActionArguments.TryGetValue("filesScope", out var filesScope) && + filesScope is ScopeDTO scope) + courseId = scope.CourseId; + + if (courseId != -1) + mentorIds = await _coursesServiceClient.GetCourseLecturersIds(courseId); + + if (mentorIds == null || !mentorIds.Contains(userId)) { - if (request.Query.TryGetValue(key, out var queryValue)) - return queryValue.ToString(); - - if (request.HasFormContentType && request.Form.TryGetValue(key, out var formValue)) - return formValue.ToString(); - - return null; + context.Result = new ContentResult + { + StatusCode = StatusCodes.Status403Forbidden, + Content = "Недостаточно прав для работы с файлами: Вы не являетесь ментором на курсе", + ContentType = "application/json" + }; + return; } + + await next.Invoke(); + } + + private static string? GetValueFromRequest(HttpRequest request, string key) + { + if (request.Query.TryGetValue(key, out var queryValue)) + return queryValue.ToString(); + + if (request.HasFormContentType && request.Form.TryGetValue(key, out var formValue)) + return formValue.ToString(); + + return null; } -} \ No newline at end of file +} diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Filters/FilesCountLimiter.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Filters/FilesCountLimiter.cs new file mode 100644 index 000000000..2f470677a --- /dev/null +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Filters/FilesCountLimiter.cs @@ -0,0 +1,27 @@ +using System.Linq; +using System.Threading.Tasks; +using HwProj.ContentService.Client; +using HwProj.Models.ContentService.DTO; +using HwProj.Models.CourseUnitType; + +namespace HwProj.APIGateway.API.Filters; + +public class FilesCountLimiter(IContentServiceClient contentServiceClient) +{ + public const long MaxSolutionFiles = 5; + + public async Task CheckCountLimit(ProcessFilesDTO processFilesDto) + { + if (processFilesDto.FilesScope.CourseUnitType == CourseUnitType.Homework) return true; + + var existingStatuses = await contentServiceClient.GetFilesStatuses(processFilesDto.FilesScope); + if (!existingStatuses.Succeeded) return false; + + var existingIds = existingStatuses.Value.Select(f => f.Id).ToList(); + if (processFilesDto.DeletingFileIds.Any(id => !existingIds.Contains(id))) + return false; + + return existingIds.Count + processFilesDto.NewFiles.Count - processFilesDto.DeletingFileIds.Count <= + MaxSolutionFiles; + } +} diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Filters/FilesPrivacyFilter.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Filters/FilesPrivacyFilter.cs new file mode 100644 index 000000000..89f979b9b --- /dev/null +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Filters/FilesPrivacyFilter.cs @@ -0,0 +1,71 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using HwProj.CoursesService.Client; +using HwProj.Models.ContentService.DTO; +using HwProj.Models.CourseUnitType; +using HwProj.SolutionsService.Client; + +namespace HwProj.APIGateway.API.Filters; + +public class FilesPrivacyFilter( + ICoursesServiceClient coursesServiceClient, + ISolutionsServiceClient solutionsServiceClient) +{ + private async Task> GetSolutionStudentIds(long solutionId) + { + var studentIds = new HashSet(); + var solution = await solutionsServiceClient.GetSolutionById(solutionId); + studentIds.Add(solution.StudentId); + + if (solution.GroupId is { } groupId) + { + var groups = await coursesServiceClient.GetGroupsById(groupId); + if (groups is [var group]) studentIds.UnionWith(group.StudentsIds.ToHashSet()); + } + + return studentIds; + } + + public async Task CheckDownloadRights(string? userId, ScopeDTO fileScope) + { + if (userId == null) return false; + + switch (fileScope.CourseUnitType) + { + case CourseUnitType.Homework: + return true; + case CourseUnitType.Solution: + { + var studentIds = await GetSolutionStudentIds(fileScope.CourseUnitId); + if (studentIds.Contains(userId)) return true; + + var mentorIds = await coursesServiceClient.GetCourseLecturersIds(fileScope.CourseId); + return mentorIds.Contains(userId); + } + default: + return false; + } + } + + public async Task CheckUploadRights(string? userId, ScopeDTO fileScope) + { + if (userId == null) return false; + + switch (fileScope.CourseUnitType) + { + case CourseUnitType.Homework: + { + var mentorIds = await coursesServiceClient.GetCourseLecturersIds(fileScope.CourseId); + return mentorIds.Contains(userId); + } + case CourseUnitType.Solution: + { + var studentIds = await GetSolutionStudentIds(fileScope.CourseUnitId); + return studentIds.Contains(userId); + } + default: + return false; + } + } +} diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/HwProj.APIGateway.API.csproj b/HwProj.APIGateway/HwProj.APIGateway.API/HwProj.APIGateway.API.csproj index 7238b2966..8f29323ea 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/HwProj.APIGateway.API.csproj +++ b/HwProj.APIGateway/HwProj.APIGateway.API/HwProj.APIGateway.API.csproj @@ -1,30 +1,29 @@  - netcoreapp2.2 + net8.0 ..\..\docker-compose.dcproj Linux ..\.. - $(CSharpLanguageVersion) $(NullableReferenceTypes) + true + $(NoWarn);1591 - - - - - - - - - + + + + + + + diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Models/CoursePreviewView.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Models/CoursePreviewView.cs index 1f9494ae4..6aadbf82c 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Models/CoursePreviewView.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Models/CoursePreviewView.cs @@ -1,23 +1,22 @@ using HwProj.Models.AuthService.DTO; -namespace HwProj.APIGateway.API.Models +namespace HwProj.APIGateway.API.Models; + +public class CoursePreviewView { - public class CoursePreviewView - { - public long Id { get; set; } - public string Name { get; set; } - public string GroupName { get; set; } - public bool IsCompleted { get; set; } - public AccountDataDto[] Mentors { get; set; } - public long? TaskId { get; set; } - } + public long Id { get; set; } + public string Name { get; set; } + public string GroupName { get; set; } + public bool IsCompleted { get; set; } + public AccountDataDto[] Mentors { get; set; } + public long? TaskId { get; set; } +} - public class CourseEvents - { - public long Id { get; set; } - public string Name { get; set; } - public string GroupName { get; set; } - public bool IsCompleted { get; set; } - public int NewStudentsCount { get; set; } - } +public class CourseEvents +{ + public long Id { get; set; } + public string Name { get; set; } + public string GroupName { get; set; } + public bool IsCompleted { get; set; } + public int NewStudentsCount { get; set; } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Models/Solutions/PostSolutionModel.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Models/Solutions/PostSolutionModel.cs new file mode 100644 index 000000000..545b0e8bc --- /dev/null +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Models/Solutions/PostSolutionModel.cs @@ -0,0 +1,55 @@ +using System.Text.Json.Serialization; + +namespace HwProj.APIGateway.API.Models.Solutions; + +public class PostSolutionModel +{ + public string? GithubUrl { get; set; } + public string? Comment { get; set; } + public string[]? GroupMateIds { get; set; } +} + +public class PostAutomatedSolutionModel +{ + /// Идентификатор задачи: название или id на HwProj, в зависимости от параметра TaskIdType + public required string TaskId { get; init; } + + /// Тип идентификатора задачи (TaskId): Title или Id на HwProj + [JsonConverter(typeof(JsonStringEnumConverter))] + public TaskIdType TaskIdType { get; init; } = TaskIdType.Id; + + /// Идентификатор студента: ФИО (в любом порядке), id на HwProj или привязанный GitHub-логин; + /// в зависимости от параметра StudentIdType + public required string StudentId { get; init; } + + /// Тип идентификатора студента (StudentId): ФИО (в любом порядке), id на HwProj или привязанный GitHub-логин + [JsonConverter(typeof(JsonStringEnumConverter))] + public StudentIdType StudentIdType { get; init; } = StudentIdType.Id; + + /// Ссылка на решение, будь то PR, репозиторий или другой источник + public string? GithubUrl { get; init; } + + /// Комментарий к решению, здесь можно оставить полезную информацию, которая будет отображаться при проверке решения в сервисе + public string? Comment { get; init; } +} + +public enum TaskIdType +{ + /// Внутренний идентификатор задачи на HwProj + Id, + + /// Полное название назади + Title +} + +public enum StudentIdType +{ + /// Внутренний идентификатор студента на HwProj + Id, + + /// Полное имя студента + FullName, + + /// Привязанный к HwProj логин студента на GitHub + GitHub +} diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Models/Solutions/SolutionPreviewView.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Models/Solutions/SolutionPreviewView.cs index 7944df290..4472e868c 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Models/Solutions/SolutionPreviewView.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Models/Solutions/SolutionPreviewView.cs @@ -1,26 +1,26 @@ using System; using HwProj.Models.AuthService.DTO; -namespace HwProj.APIGateway.API.Models.Solutions +namespace HwProj.APIGateway.API.Models.Solutions; + +public class SolutionPreviewView { - public class SolutionPreviewView - { - public long SolutionId { get; set; } - public AccountDataDto Student { get; set; } - public string CourseTitle { get; set; } - public long CourseId { get; set; } - public string HomeworkTitle { get; set; } - public string TaskTitle { get; set; } - public long TaskId { get; set; } - public DateTime PublicationDate { get; set; } - public long? GroupId { get; set; } - public bool IsFirstTry { get; set; } - public bool SentAfterDeadline { get; set; } - public bool IsCourseCompleted { get; set; } - } + public long SolutionId { get; set; } + public AccountDataDto Student { get; set; } + public string CourseTitle { get; set; } + public long CourseId { get; set; } + public string HomeworkTitle { get; set; } + public string TaskTitle { get; set; } + public long TaskId { get; set; } + public DateTime PublicationDate { get; set; } + public long? GroupId { get; set; } + public bool IsFirstTry { get; set; } + public bool SentAfterDeadline { get; set; } + public bool IsCourseCompleted { get; set; } + public bool IsTest { get; set; } +} - public class UnratedSolutionPreviews - { - public SolutionPreviewView[] UnratedSolutions { get; set; } - } +public class UnratedSolutionPreviews +{ + public SolutionPreviewView[] UnratedSolutions { get; set; } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Models/Solutions/UserTaskSolutions.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Models/Solutions/UserTaskSolutions.cs index 668f585d7..7f79d2cd2 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Models/Solutions/UserTaskSolutions.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Models/Solutions/UserTaskSolutions.cs @@ -1,68 +1,67 @@ using HwProj.Models.AuthService.DTO; using HwProj.Models.CoursesService.DTO; -using HwProj.Models.CoursesService.ViewModels; using HwProj.Models.SolutionsService; using HwProj.Models.StatisticsService; -namespace HwProj.APIGateway.API.Models.Solutions -{ - public class UserTaskSolutions - { - public GetSolutionModel[] Solutions { get; set; } - public StudentDataDto Student { get; set; } - } +namespace HwProj.APIGateway.API.Models.Solutions; - public class UserTaskSolutions2 - { - public int MaxRating { get; set; } - public string Title { get; set; } - public string[] Tags { get; set; } - public string TaskId { get; set; } - public GetSolutionModel[] Solutions { get; set; } - } +public class UserTaskSolutions +{ + public GetSolutionModel[] Solutions { get; set; } + public StudentDataDto Student { get; set; } + public bool HasDifferentReviewer { get; set; } +} - public class TaskSolutionStatisticsPageData - { - public TaskSolutions[] TaskSolutions { get; set; } - public long CourseId { get; set; } - public HomeworksGroupSolutionStats[] StatsForTasks { get; set; } - } +public class UserTaskSolutions2 +{ + public int MaxRating { get; set; } + public string Title { get; set; } + public string[] Tags { get; set; } + public string TaskId { get; set; } + public GetSolutionModel[] Solutions { get; set; } +} - public class UserTaskSolutionsPageData - { - public long CourseId { get; set; } - public AccountDataDto[] CourseMates { get; set; } - public HomeworksGroupUserTaskSolutions[] TaskSolutions { get; set; } - } +public class TaskSolutionStatisticsPageData +{ + public AccountDataDto[] CourseMentors { get; set; } + public TaskSolutions[] TaskSolutions { get; set; } + public long CourseId { get; set; } + public HomeworksGroupSolutionStats[] StatsForTasks { get; set; } +} - public class HomeworksGroupUserTaskSolutions - { - public string? GroupTitle { get; set; } - public HomeworkUserTaskSolutions[] HomeworkSolutions { get; set; } - } +public class UserTaskSolutionsPageData +{ + public long CourseId { get; set; } + public AccountDataDto[] CourseMates { get; set; } + public HomeworksGroupUserTaskSolutions[] TaskSolutions { get; set; } +} - public class HomeworkUserTaskSolutions - { - public string HomeworkTitle { get; set; } - public UserTaskSolutions2[] StudentSolutions { get; set; } - } +public class HomeworksGroupUserTaskSolutions +{ + public string? GroupTitle { get; set; } + public HomeworkUserTaskSolutions[] HomeworkSolutions { get; set; } +} +public class HomeworkUserTaskSolutions +{ + public string HomeworkTitle { get; set; } + public UserTaskSolutions2[] StudentSolutions { get; set; } +} - public class TaskSolutions - { - public long TaskId { get; set; } - public UserTaskSolutions[] StudentSolutions { get; set; } - } +public class TaskSolutions +{ + public long TaskId { get; set; } + public UserTaskSolutions[] StudentSolutions { get; set; } +} - public class HomeworksGroupSolutionStats - { - public string? GroupTitle { get; set; } - public HomeworkSolutionsStats[] StatsForHomeworks { get; set; } - } +public class HomeworksGroupSolutionStats +{ + public string? GroupTitle { get; set; } + public HomeworkSolutionsStats[] StatsForHomeworks { get; set; } +} - public class HomeworkSolutionsStats - { - public string HomeworkTitle { get; set; } - public TaskSolutionsStats[] StatsForTasks { get; set; } - } +public class HomeworkSolutionsStats +{ + public string HomeworkTitle { get; set; } + public TaskSolutionsStats[] StatsForTasks { get; set; } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Models/Statistics/AdvancedCourseStatisticsViewModel.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Models/Statistics/AdvancedCourseStatisticsViewModel.cs index ebecaa9b1..6984237d1 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Models/Statistics/AdvancedCourseStatisticsViewModel.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Models/Statistics/AdvancedCourseStatisticsViewModel.cs @@ -1,14 +1,13 @@ using HwProj.Models.CoursesService.ViewModels; using HwProj.Models.StatisticsService; -namespace HwProj.APIGateway.API.Models.Statistics +namespace HwProj.APIGateway.API.Models.Statistics; + +public class AdvancedCourseStatisticsViewModel { - public class AdvancedCourseStatisticsViewModel - { - public CoursePreview Course { get; set; } - public HomeworkViewModel[] Homeworks { get; set; } - public StatisticsCourseMatesModel[] StudentStatistics { get; set; } - public StatisticsCourseMeasureSolutionModel[] AverageStudentSolutions { get; set; } - public StatisticsCourseMeasureSolutionModel[] BestStudentSolutions { get; set; } - } -} \ No newline at end of file + public CoursePreview Course { get; set; } + public HomeworkViewModel[] Homeworks { get; set; } + public StatisticsCourseMatesModel[] StudentStatistics { get; set; } + public StatisticsCourseMeasureSolutionModel[] AverageStudentSolutions { get; set; } + public StatisticsCourseMeasureSolutionModel[] BestStudentSolutions { get; set; } +} diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Models/Statistics/StatisticsCourseMatesModel.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Models/Statistics/StatisticsCourseMatesModel.cs index f97403cf1..5bc6f4609 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Models/Statistics/StatisticsCourseMatesModel.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Models/Statistics/StatisticsCourseMatesModel.cs @@ -3,14 +3,13 @@ using HwProj.Models.AuthService.DTO; using HwProj.Models.StatisticsService; -namespace HwProj.APIGateway.API.Models.Statistics +namespace HwProj.APIGateway.API.Models.Statistics; + +public class StatisticsCourseMatesModel { - public class StatisticsCourseMatesModel - { - public string Id { get; set; } - public string Name { get; set; } - public string Surname { get; set; } - public AccountDataDto[] Reviewers { get; set; } = Array.Empty(); - public List Homeworks { get; set; } = new List(); - } + public string Id { get; set; } + public string Name { get; set; } + public string Surname { get; set; } + public AccountDataDto[] Reviewers { get; set; } = Array.Empty(); + public List Homeworks { get; set; } = new(); } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Models/Statistics/StatisticsLecturersModel.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Models/Statistics/StatisticsLecturersModel.cs index c130d7092..4147c9280 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Models/Statistics/StatisticsLecturersModel.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Models/Statistics/StatisticsLecturersModel.cs @@ -1,11 +1,10 @@ using HwProj.Models.AuthService.DTO; -namespace HwProj.APIGateway.API.Models.Statistics +namespace HwProj.APIGateway.API.Models.Statistics; + +public class StatisticsLecturersModel { - public class StatisticsLecturersModel - { - public AccountDataDto Lecturer { get; set; } - public int NumberOfCheckedSolutions { get; set; } - public int NumberOfCheckedUniqueSolutions { get; set; } - } + public AccountDataDto Lecturer { get; set; } + public int NumberOfCheckedSolutions { get; set; } + public int NumberOfCheckedUniqueSolutions { get; set; } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Models/SystemInfo.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Models/SystemInfo.cs index 56c142588..9d483c581 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Models/SystemInfo.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Models/SystemInfo.cs @@ -1,8 +1,7 @@ -namespace HwProj.APIGateway.API.Models +namespace HwProj.APIGateway.API.Models; + +public class SystemInfo { - public class SystemInfo - { - public string Service { get; set; } - public bool IsAvailable { get; set; } - } + public string Service { get; set; } + public bool IsAvailable { get; set; } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Models/Tasks/TaskDeadlineView.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Models/Tasks/TaskDeadlineView.cs index 001342249..015ed4265 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Models/Tasks/TaskDeadlineView.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Models/Tasks/TaskDeadlineView.cs @@ -1,14 +1,13 @@ using HwProj.Models.CoursesService.DTO; using HwProj.Models.SolutionsService; -namespace HwProj.APIGateway.API.Models.Tasks +namespace HwProj.APIGateway.API.Models.Tasks; + +public class TaskDeadlineView { - public class TaskDeadlineView - { - public TaskDeadlineDto Deadline { get; set; } - public SolutionState? SolutionState { get; set; } - public long? Rating { get; set; } - public long MaxRating { get; set; } - public bool DeadlinePast { get; set; } - } + public TaskDeadlineDto Deadline { get; set; } + public SolutionState? SolutionState { get; set; } + public long? Rating { get; set; } + public long MaxRating { get; set; } + public bool DeadlinePast { get; set; } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Models/UserDataDto.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Models/UserDataDto.cs index f4af2a43c..bbd4cbfd0 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Models/UserDataDto.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Models/UserDataDto.cs @@ -1,12 +1,11 @@ using HwProj.APIGateway.API.Models.Tasks; using HwProj.Models.AuthService.DTO; -namespace HwProj.APIGateway.API.Models +namespace HwProj.APIGateway.API.Models; + +public class UserDataDto { - public class UserDataDto - { - public AccountDataDto UserData { get; set; } - public CourseEvents[] CourseEvents { get; set; } - public TaskDeadlineView[] TaskDeadlines { get; set; } - } + public AccountDataDto UserData { get; set; } + public CourseEvents[] CourseEvents { get; set; } + public TaskDeadlineView[] TaskDeadlines { get; set; } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Program.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Program.cs index 47a2138f8..71679216f 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Program.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Program.cs @@ -2,25 +2,21 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; -namespace HwProj.APIGateway.API +namespace HwProj.APIGateway.API; + +public static class Program { - public static class Program + public static void Main(string[] args) { - public static void Main(string[] args) - { - WebHost.CreateDefaultBuilder(args) - .UseStartup() - .ConfigureAppConfiguration((hostingContext, config) => - { - config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath) - .AddEnvironmentVariables(); - }) - .ConfigureKestrel(options => - { - options.Limits.MaxRequestBodySize = 200 * 1024 * 1024; - }) - .Build() - .Run(); - } + WebHost.CreateDefaultBuilder(args) + .UseStartup() + .ConfigureAppConfiguration((hostingContext, config) => + { + config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath) + .AddEnvironmentVariables(); + }) + .ConfigureKestrel(options => { options.Limits.MaxRequestBodySize = 200 * 1024 * 1024; }) + .Build() + .Run(); } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Startup.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Startup.cs index cf053dec6..ef7c604ad 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Startup.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Startup.cs @@ -1,72 +1,144 @@ -using HwProj.AuthService.Client; +using System.Collections.Generic; +using System.Text; +using System.Text.Json.Serialization; +using HwProj.APIGateway.API.Filters; +using HwProj.AuthService.Client; using HwProj.ContentService.Client; using HwProj.CoursesService.Client; using HwProj.NotificationsService.Client; using HwProj.SolutionsService.Client; -using HwProj.Utils.Auth; -using HwProj.Utils.Configuration; -using HwProj.APIGateway.API.Filters; +using IStudentsInfo; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.IdentityModel.Tokens; -using IStudentsInfo; +using Microsoft.OpenApi.Models; using StudentsInfo; -namespace HwProj.APIGateway.API +namespace HwProj.APIGateway.API; + +public class Startup { - public class Startup + public Startup(IConfiguration configuration) { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } + Configuration = configuration; + } - public IConfiguration Configuration { get; } + public IConfiguration Configuration { get; } - public void ConfigureServices(IServiceCollection services) - { - services.Configure(options => { options.MultipartBodyLengthLimit = 200 * 1024 * 1024; }); - services.ConfigureHwProjServices("API Gateway"); - services.AddSingleton(provider => - new StudentsInformationProvider(Configuration["StudentsInfo:Login"], - Configuration["StudentsInfo:Password"], - Configuration["StudentsInfo:LdapHost"], int.Parse(Configuration["StudentsInfo:LdapPort"]), - Configuration["StudentsInfo:SearchBase"])); - const string authenticationProviderKey = "GatewayKey"; + public void ConfigureServices(IServiceCollection services) + { + services + .AddCors() + .AddControllers() + .AddJsonOptions(options => + options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles); + + services.AddHttpContextAccessor(); + services.AddAutoMapper(x => x.AddProfile()); + services.Configure(options => { options.MultipartBodyLengthLimit = 200 * 1024 * 1024; }); + ConfigureHwProjServiceSwaggerGen(services); - services.AddAuthentication() - .AddJwtBearer(authenticationProviderKey, x => + services.AddSingleton(provider => + new StudentsInformationProvider(Configuration["StudentsInfo:Login"], + Configuration["StudentsInfo:Password"], + Configuration["StudentsInfo:LdapHost"], int.Parse(Configuration["StudentsInfo:LdapPort"]), + Configuration["StudentsInfo:SearchBase"])); + + var appSettings = Configuration.GetSection("Security"); + + services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, x => + { + x.RequireHttpsMetadata = false; + x.TokenValidationParameters = new TokenValidationParameters { - x.RequireHttpsMetadata = false; - x.TokenValidationParameters = new TokenValidationParameters - { - ValidIssuer = "AuthService", - ValidateIssuer = true, - ValidateAudience = false, - ValidateLifetime = true, - IssuerSigningKey = AuthorizationKey.SecurityKey, - ValidateIssuerSigningKey = true - }; - }); + ValidIssuer = "AuthService", + ValidateIssuer = true, + ValidateAudience = false, + ValidateLifetime = true, + IssuerSigningKey = + new SymmetricSecurityKey(Encoding.ASCII.GetBytes(appSettings["SecurityKey"])), + ValidateIssuerSigningKey = true + }; + }); + + services.AddHttpClient(); + services.AddHttpContextAccessor(); - services.AddHttpClient(); - services.AddHttpContextAccessor(); + services.AddAuthServiceClient(); + services.AddCoursesServiceClient(); + services.AddSolutionServiceClient(); + services.AddNotificationsServiceClient(); + services.AddContentServiceClient(); - services.AddAuthServiceClient(); - services.AddCoursesServiceClient(); - services.AddSolutionServiceClient(); - services.AddNotificationsServiceClient(); - services.AddContentServiceClient(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + } - services.AddScoped(); - } + public void Configure(IApplicationBuilder app, IHostEnvironment env) + { + if (env.IsDevelopment()) + app.UseDeveloperExceptionPage() + .UseSwagger() + .UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "API Gateway"); }); + else + app.UseHsts(); + + app.UseRouting(); + app.UseAuthentication(); + app.UseAuthorization(); + app.UseCors(x => x + .AllowAnyMethod() + .AllowAnyHeader() + .SetIsOriginAllowed(_ => true) + .AllowCredentials()); + + app.UseEndpoints(x => x.MapControllers()); + } - public void Configure(IApplicationBuilder app, IHostingEnvironment env) + private static void ConfigureHwProjServiceSwaggerGen(IServiceCollection services) + { + services.AddSwaggerGen(c => { - app.ConfigureHwProj(env, "API Gateway"); - } + c.SwaggerDoc("v1", new OpenApiInfo { Title = "API Gateway", Version = "v1" }); + c.CustomOperationIds(apiDesc => + { + var controllerName = apiDesc.ActionDescriptor.RouteValues["controller"]; + var actionName = apiDesc.ActionDescriptor.RouteValues["action"]; + return $"{controllerName}{actionName}"; + }); + c.AddSecurityDefinition("Bearer", + new OpenApiSecurityScheme + { + In = ParameterLocation.Header, + Description = "Please enter into field the word 'Bearer' following by space and JWT", + Name = "Authorization", + Type = SecuritySchemeType.ApiKey + }); + c.AddSecurityRequirement( + new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Id = "Bearer", + Type = ReferenceType.SecurityScheme + } + }, + new List() + } + }); + }); } } diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/appsettings.json b/HwProj.APIGateway/HwProj.APIGateway.API/appsettings.json index 92453a812..b3e146a09 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/appsettings.json +++ b/HwProj.APIGateway/HwProj.APIGateway.API/appsettings.json @@ -5,7 +5,10 @@ "Notifications": "http://localhost:5006", "Solutions": "http://localhost:5007", "Content": "http://localhost:5008" - }, + }, + "Security": { + "SecurityKey": "U8_.wpvk93fPWG InviteNewLecturer(InviteLecturerViewModel model } [HttpGet("findByEmail/{email}")] - [ProducesResponseType(typeof(User), (int)HttpStatusCode.OK)] + [ProducesResponseType(typeof(AccountDataDto), (int)HttpStatusCode.OK)] public async Task FindByEmail(string email) { var user = await _userManager.FindByEmailAsync(email); - return Ok(user); - } - - [HttpGet("getRole")] - [ProducesResponseType(typeof(string), (int)HttpStatusCode.OK)] - public async Task GetRolesAsync([FromBody] User user) - { var roles = await _userManager.GetRolesAsync(user); - return Ok(roles[0]); + return Ok(user.ToAccountDataDto(roles.First())); } [HttpGet("getAllStudents")] @@ -141,7 +134,7 @@ public async Task GetAllStudents() public async Task GetAllLecturers() { var allLecturers = await _accountService.GetUsersInRole(Roles.LecturerRole); - var result = allLecturers.ToArray(); + var result = allLecturers.Select(x => x.ToAccountDataDto(Roles.LecturerRole)).ToArray(); return Ok(result); } diff --git a/HwProj.AuthService/HwProj.AuthService.API/Dockerfile b/HwProj.AuthService/HwProj.AuthService.API/Dockerfile index 22da9c224..a54124dd0 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Dockerfile +++ b/HwProj.AuthService/HwProj.AuthService.API/Dockerfile @@ -1,18 +1,20 @@ -FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY ["Directory.Build.props", "Directory.Build.props"] COPY ["HwProj.AuthService/HwProj.AuthService.API/", "HwProj.AuthService/HwProj.AuthService.API/"] -COPY ["HwProj.Common/HwProj.Utils/", "HwProj.Common/HwProj.Utils/"] -COPY ["HwProj.EventBus/HwProj.EventBus.Client/", "HwProj.EventBus/HwProj.EventBus.Client/"] +COPY ["HwProj.Common/HwProj.Common.Net8/", "HwProj.Common/HwProj.Common.Net8/"] COPY ["HwProj.Common/HwProj.Models/", "HwProj.Common/HwProj.Models/"] COPY ["HwProj.Common/HwProj.Repositories/", "HwProj.Common/HwProj.Repositories/"] +COPY ["HwProj.Common/HwProj.Repositories.Net8/", "HwProj.Common/HwProj.Repositories.Net8/"] +COPY ["HwProj.EventBus/HwProj.EventBus.Client/", "HwProj.EventBus/HwProj.EventBus.Client/"] +COPY ["HwProj.NotificationsService/HwProj.NotificationService.Events/", "HwProj.NotificationsService/HwProj.NotificationService.Events/"] WORKDIR "/src/HwProj.AuthService/HwProj.AuthService.API" RUN dotnet publish "HwProj.AuthService.API.csproj" -c Release -o /app/publish -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim AS final +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final WORKDIR /app COPY --from=build /app/publish . diff --git a/HwProj.AuthService/HwProj.AuthService.API/Extensions/MappingExtensions.cs b/HwProj.AuthService/HwProj.AuthService.API/Extensions/MappingExtensions.cs new file mode 100644 index 000000000..b9fb1d328 --- /dev/null +++ b/HwProj.AuthService/HwProj.AuthService.API/Extensions/MappingExtensions.cs @@ -0,0 +1,23 @@ +using HwProj.AuthService.API.Models; +using HwProj.Models.AuthService.DTO; + +namespace HwProj.AuthService.API.Extensions +{ + public static class MappingExtensions + { + public static AccountDataDto ToAccountDataDto(this User user, string role) + { + return new AccountDataDto( + user.Id, + user.Name, + user.Surname, + user.Email, + role, + user.IsExternalAuth, + user.MiddleName, + user.GitHubId, + user.CompanyName, + user.Bio); + } + } +} diff --git a/HwProj.AuthService/HwProj.AuthService.API/HwProj.AuthService.API.csproj b/HwProj.AuthService/HwProj.AuthService.API/HwProj.AuthService.API.csproj index ee29e95ca..1eaa0766d 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/HwProj.AuthService.API.csproj +++ b/HwProj.AuthService/HwProj.AuthService.API/HwProj.AuthService.API.csproj @@ -1,34 +1,29 @@  - netcoreapp2.2 + net8.0 Linux ..\..\docker-compose.dcproj ..\.. $(CSharpLanguageVersion) 603911e4-ace8-4439-96f8-1705a0dae761 - $(NullableReferenceTypes) + disable - - - - - - - + + + + + - + - - - - + diff --git a/HwProj.AuthService/HwProj.AuthService.API/Models/ExpertData.cs b/HwProj.AuthService/HwProj.AuthService.API/Models/ExpertData.cs index b54695d9c..c95983f08 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Models/ExpertData.cs +++ b/HwProj.AuthService/HwProj.AuthService.API/Models/ExpertData.cs @@ -1,7 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using HwProj.Models.AuthService.ViewModels; -using HwProj.Repositories; +using HwProj.Repositories.Net8; namespace HwProj.AuthService.API.Models { diff --git a/HwProj.AuthService/HwProj.AuthService.API/Models/IdentityContext.cs b/HwProj.AuthService/HwProj.AuthService.API/Models/IdentityContext.cs index 6991c6bfc..564a283e1 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Models/IdentityContext.cs +++ b/HwProj.AuthService/HwProj.AuthService.API/Models/IdentityContext.cs @@ -1,5 +1,4 @@ -using HwProj.Models.AuthService.ViewModels; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; namespace HwProj.AuthService.API.Models diff --git a/HwProj.AuthService/HwProj.AuthService.API/Models/User.cs b/HwProj.AuthService/HwProj.AuthService.API/Models/User.cs new file mode 100644 index 000000000..e2058f1d1 --- /dev/null +++ b/HwProj.AuthService/HwProj.AuthService.API/Models/User.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.Identity; + +namespace HwProj.AuthService.API.Models +{ + public class User : IdentityUser + { + public string GitHubId { get; set; } + + public string Name { get; set; } + + public string Surname { get; set; } + + public string MiddleName { get; set; } + + public bool IsExternalAuth { get; set; } + + public string Bio { get; set; } + + public string CompanyName { get; set; } + + public User() + { + } + } +} diff --git a/HwProj.AuthService/HwProj.AuthService.API/Repositories/ExpertsRepository.cs b/HwProj.AuthService/HwProj.AuthService.API/Repositories/ExpertsRepository.cs index 1470ae60e..bb6059771 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Repositories/ExpertsRepository.cs +++ b/HwProj.AuthService/HwProj.AuthService.API/Repositories/ExpertsRepository.cs @@ -1,9 +1,7 @@ using System.Linq; using System.Threading.Tasks; using HwProj.AuthService.API.Models; -using HwProj.Models.AuthService.ViewModels; -using HwProj.Repositories; -using Microsoft.AspNetCore.Identity; +using HwProj.Repositories.Net8; using Microsoft.EntityFrameworkCore; namespace HwProj.AuthService.API.Repositories diff --git a/HwProj.AuthService/HwProj.AuthService.API/Repositories/IExpertsRepository.cs b/HwProj.AuthService/HwProj.AuthService.API/Repositories/IExpertsRepository.cs index b619f530a..f16ea98b5 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Repositories/IExpertsRepository.cs +++ b/HwProj.AuthService/HwProj.AuthService.API/Repositories/IExpertsRepository.cs @@ -1,8 +1,6 @@ using System.Threading.Tasks; using HwProj.AuthService.API.Models; -using HwProj.Models.AuthService.DTO; -using HwProj.Models.AuthService.ViewModels; -using HwProj.Repositories; +using HwProj.Repositories.Net8; namespace HwProj.AuthService.API.Repositories { diff --git a/HwProj.AuthService/HwProj.AuthService.API/RoleInitializer.cs b/HwProj.AuthService/HwProj.AuthService.API/RoleInitializer.cs index 8fd2e8ea2..f8cb0f20d 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/RoleInitializer.cs +++ b/HwProj.AuthService/HwProj.AuthService.API/RoleInitializer.cs @@ -1,29 +1,33 @@ using Microsoft.AspNetCore.Identity; using System.Threading.Tasks; -using HwProj.AuthService.API.Events; using HwProj.EventBus.Client.Interfaces; using HwProj.Models.Roles; -using HwProj.Models.AuthService.ViewModels; +using HwProj.NotificationService.Events.AuthService; +using User = HwProj.AuthService.API.Models.User; namespace HwProj.AuthService.API { public class RoleInitializer { + private static IdentityRole _lecturer = new IdentityRole(Roles.LecturerRole); + private static IdentityRole _student = new IdentityRole(Roles.StudentRole); + private static IdentityRole _expert = new IdentityRole(Roles.ExpertRole); + public static async Task InitializeAsync(UserManager userManager, RoleManager roleManager, IEventBus eventBus) { if(await roleManager.FindByNameAsync(Roles.LecturerRole) == null) { - await roleManager.CreateAsync(Roles.Lecturer); + await roleManager.CreateAsync(_lecturer); } if (await roleManager.FindByNameAsync(Roles.StudentRole) == null) { - await roleManager.CreateAsync(Roles.Student); + await roleManager.CreateAsync(_student); } if (await roleManager.FindByNameAsync(Roles.ExpertRole) == null) { - await roleManager.CreateAsync(Roles.Expert); + await roleManager.CreateAsync(_expert); } const string email = "admin@gmail.com"; diff --git a/HwProj.AuthService/HwProj.AuthService.API/Services/AccountService.cs b/HwProj.AuthService/HwProj.AuthService.API/Services/AccountService.cs index 945e48e58..706886b30 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Services/AccountService.cs +++ b/HwProj.AuthService/HwProj.AuthService.API/Services/AccountService.cs @@ -8,17 +8,15 @@ using AutoMapper; using HwProj.AuthService.API.Extensions; using HwProj.Models.Roles; -using HwProj.AuthService.API.Events; -using HwProj.AuthService.API.Repositories; using HwProj.EventBus.Client.Interfaces; using HwProj.Models.AuthService.DTO; using HwProj.Models.AuthService.ViewModels; using HwProj.Models.Result; -using HwProj.Utils.Authorization; +using HwProj.NotificationService.Events.AuthService; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Octokit; -using User = HwProj.Models.AuthService.ViewModels.User; +using User = HwProj.AuthService.API.Models.User; namespace HwProj.AuthService.API.Services @@ -95,6 +93,11 @@ public async Task GetAccountDataByEmailAsync(string email) public async Task> RegisterUserAsync(RegisterDataDTO model) { + model.Email = model.Email.Trim(); + model.Name = model.Name.Trim(); + model.Surname = model.Surname.Trim(); + model.MiddleName = model.MiddleName.Trim(); + if (await _userManager.FindByEmailAsync(model.Email) != null) return Result.Failed("Пользователь уже зарегистрирован"); diff --git a/HwProj.AuthService/HwProj.AuthService.API/Services/AuthTokenService.cs b/HwProj.AuthService/HwProj.AuthService.API/Services/AuthTokenService.cs index 3c5ea76a5..528a019ab 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Services/AuthTokenService.cs +++ b/HwProj.AuthService/HwProj.AuthService.API/Services/AuthTokenService.cs @@ -10,8 +10,8 @@ using HwProj.Models.Roles; using Microsoft.Extensions.Configuration; using HwProj.Models.AuthService.DTO; -using HwProj.Models.AuthService.ViewModels; using HwProj.Models.Result; +using User = HwProj.AuthService.API.Models.User; namespace HwProj.AuthService.API.Services { diff --git a/HwProj.AuthService/HwProj.AuthService.API/Services/ExpertsService.cs b/HwProj.AuthService/HwProj.AuthService.API/Services/ExpertsService.cs index b17d402e0..bc48b14b2 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Services/ExpertsService.cs +++ b/HwProj.AuthService/HwProj.AuthService.API/Services/ExpertsService.cs @@ -9,7 +9,7 @@ using HwProj.Models.Result; using HwProj.Models.Roles; using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore.Internal; +using User = HwProj.AuthService.API.Models.User; namespace HwProj.AuthService.API.Services { @@ -68,7 +68,7 @@ await _expertsRepository.AddAsync(new ExpertData Id = user.Id, LecturerId = lecturerId, IsProfileEdited = false, - Tags = model.Tags.Join(";") + Tags = string.Join(';', model.Tags) }); return Result.Success(); @@ -171,7 +171,7 @@ public async Task UpdateExpertTags(string lecturerId, UpdateExpertTagsDT await _expertsRepository.UpdateAsync(updateExpertTagsDto.ExpertId, data => new ExpertData() { - Tags = updateExpertTagsDto.Tags.Join(";") + Tags = string.Join(';', updateExpertTagsDto.Tags) }); return Result.Success(); diff --git a/HwProj.AuthService/HwProj.AuthService.API/Services/IAccountService.cs b/HwProj.AuthService/HwProj.AuthService.API/Services/IAccountService.cs index 463161087..ca7d3c1d4 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Services/IAccountService.cs +++ b/HwProj.AuthService/HwProj.AuthService.API/Services/IAccountService.cs @@ -4,6 +4,7 @@ using HwProj.Models.AuthService.DTO; using HwProj.Models.AuthService.ViewModels; using HwProj.Models.Result; +using User = HwProj.AuthService.API.Models.User; namespace HwProj.AuthService.API.Services { diff --git a/HwProj.AuthService/HwProj.AuthService.API/Services/IAuthTokenService.cs b/HwProj.AuthService/HwProj.AuthService.API/Services/IAuthTokenService.cs index 18ed24100..9dc2b45fc 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Services/IAuthTokenService.cs +++ b/HwProj.AuthService/HwProj.AuthService.API/Services/IAuthTokenService.cs @@ -1,7 +1,7 @@ using HwProj.Models.AuthService.DTO; -using HwProj.Models.AuthService.ViewModels; using System.Threading.Tasks; using HwProj.Models.Result; +using User = HwProj.AuthService.API.Models.User; namespace HwProj.AuthService.API.Services { diff --git a/HwProj.AuthService/HwProj.AuthService.API/Services/IUserManager.cs b/HwProj.AuthService/HwProj.AuthService.API/Services/IUserManager.cs index 9ce9db520..f041a232b 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Services/IUserManager.cs +++ b/HwProj.AuthService/HwProj.AuthService.API/Services/IUserManager.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Threading.Tasks; -using HwProj.Models.AuthService.ViewModels; using Microsoft.AspNetCore.Identity; +using User = HwProj.AuthService.API.Models.User; namespace HwProj.AuthService.API.Services { diff --git a/HwProj.AuthService/HwProj.AuthService.API/Services/ProxyUserManager.cs b/HwProj.AuthService/HwProj.AuthService.API/Services/ProxyUserManager.cs index 533b149cb..593a7e07e 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Services/ProxyUserManager.cs +++ b/HwProj.AuthService/HwProj.AuthService.API/Services/ProxyUserManager.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Threading.Tasks; -using HwProj.Models.AuthService.ViewModels; using Microsoft.AspNetCore.Identity; +using User = HwProj.AuthService.API.Models.User; namespace HwProj.AuthService.API.Services { diff --git a/HwProj.AuthService/HwProj.AuthService.API/Startup.cs b/HwProj.AuthService/HwProj.AuthService.API/Startup.cs index 07990e8ff..47cd285cd 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/Startup.cs +++ b/HwProj.AuthService/HwProj.AuthService.API/Startup.cs @@ -1,5 +1,5 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; +using System.Text.Json.Serialization; +using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using HwProj.AuthService.API.Models; @@ -7,13 +7,11 @@ using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using HwProj.AuthService.API.Services; +using HwProj.Common.Net8; +using HwProj.EventBus.Client; using HwProj.EventBus.Client.Interfaces; -using Microsoft.IdentityModel.Tokens; -using Microsoft.AspNetCore.Authentication.JwtBearer; -using HwProj.Utils.Configuration; -using HwProj.Models.AuthService.ViewModels; -using HwProj.Models.Roles; -using HwProj.Utils.Auth; +using Microsoft.Extensions.Hosting; +using User = HwProj.AuthService.API.Models.User; namespace HwProj.AuthService.API { @@ -28,26 +26,13 @@ public Startup(IConfiguration configuration) public void ConfigureServices(IServiceCollection services) { - services.ConfigureHwProjServices("AuthService API"); - - //var appSettingsSection = Configuration.GetSection("AppSettings"); - //services.Configure(appSettingsSection); - - services.AddAuthentication(options => { options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; }) - .AddJwtBearer(x => - { - x.RequireHttpsMetadata = false; //TODO: dev env setting - x.TokenValidationParameters = new TokenValidationParameters - { - ValidIssuer = "AuthService", - ValidateIssuer = true, - ValidateAudience = false, - ValidateLifetime = true, - IssuerSigningKey = AuthorizationKey.SecurityKey, - ValidateIssuerSigningKey = true - }; - }); + services + .AddCors() + .AddControllers() + .AddJsonOptions(options => + options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles); + services.AddAutoMapper(x => x.AddProfile()); services.AddHttpClient(); var connectionString = ConnectionString.GetConnectionString(Configuration); @@ -77,22 +62,32 @@ public void ConfigureServices(IServiceCollection services) .AddScoped(); } - public void Configure(IApplicationBuilder app, IHostingEnvironment env, IdentityContext context) + public void Configure(IApplicationBuilder app, IHostEnvironment env, IdentityContext context) { - app.ConfigureHwProj(env, "AuthService API", context); + if (env.IsDevelopment()) app.UseDeveloperExceptionPage(); + else app.UseHsts(); - using (var scope = app.ApplicationServices.CreateScope()) - { - var userManager = scope.ServiceProvider.GetService(typeof(UserManager)) as UserManager; + app.UseRouting(); + app.UseAuthentication(); + app.UseCors(x => x + .AllowAnyMethod() + .AllowAnyHeader() + .SetIsOriginAllowed(_ => true) + .AllowCredentials()); - var rolesManager = - scope.ServiceProvider.GetService(typeof(RoleManager)) as RoleManager; - var eventBus = scope.ServiceProvider.GetService(); + app.UseEndpoints(x => x.MapControllers()); - if (env.IsDevelopment()) - { - RoleInitializer.InitializeAsync(userManager, rolesManager, eventBus).Wait(); - } + app.UseDatabase(env, context); + + using var scope = app.ApplicationServices.CreateScope(); + var userManager = scope.ServiceProvider.GetService>(); + + var rolesManager = scope.ServiceProvider.GetService>(); + var eventBus = scope.ServiceProvider.GetService(); + + if (env.IsDevelopment()) + { + RoleInitializer.InitializeAsync(userManager, rolesManager, eventBus).Wait(); } } } diff --git a/HwProj.AuthService/HwProj.AuthService.API/appsettings.json b/HwProj.AuthService/HwProj.AuthService.API/appsettings.json index 34f0e2986..bb18739ae 100644 --- a/HwProj.AuthService/HwProj.AuthService.API/appsettings.json +++ b/HwProj.AuthService/HwProj.AuthService.API/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "DefaultConnectionForWindows": "Server=(localdb)\\mssqllocaldb;Database=AuthServiceDB;Trusted_Connection=True;", + "DefaultConnectionForWindows": "Server=(localdb)\\mssqllocaldb;Database=AuthServiceDB;Trusted_Connection=True;TrustServerCertificate=true;", "DefaultConnectionForLinux": "Server=localhost,1433;Database=AuthServiceDB;User ID=SA;Password=password_1234;" }, "Logging": { diff --git a/HwProj.AuthService/HwProj.AuthService.Client/AuthServiceClient.cs b/HwProj.AuthService/HwProj.AuthService.Client/AuthServiceClient.cs index 24652becb..bf2d29112 100644 --- a/HwProj.AuthService/HwProj.AuthService.Client/AuthServiceClient.cs +++ b/HwProj.AuthService/HwProj.AuthService.Client/AuthServiceClient.cs @@ -163,8 +163,8 @@ public async Task FindByEmailAsync(string email) }; var response = await _httpClient.SendAsync(httpRequest); - var user = await response.DeserializeAsync(); - return user?.Id; + var user = await response.DeserializeAsync(); + return user?.UserId; } public async Task GetAllStudents() @@ -177,14 +177,14 @@ public async Task GetAllStudents() return await response.DeserializeAsync().ConfigureAwait(false); } - public async Task GetAllLecturers() + public async Task GetAllLecturers() { using var httpRequest = new HttpRequestMessage( HttpMethod.Get, _authServiceUri + "api/account/getAllLecturers"); var response = await _httpClient.SendAsync(httpRequest); - return await response.DeserializeAsync().ConfigureAwait(false); + return await response.DeserializeAsync().ConfigureAwait(false); } public async Task Ping() diff --git a/HwProj.AuthService/HwProj.AuthService.Client/IAuthServiceClient.cs b/HwProj.AuthService/HwProj.AuthService.Client/IAuthServiceClient.cs index 67c020ca6..63d678991 100644 --- a/HwProj.AuthService/HwProj.AuthService.Client/IAuthServiceClient.cs +++ b/HwProj.AuthService/HwProj.AuthService.Client/IAuthServiceClient.cs @@ -18,7 +18,7 @@ public interface IAuthServiceClient Task InviteNewLecturer(InviteLecturerViewModel model); Task FindByEmailAsync(string email); Task GetAllStudents(); - Task GetAllLecturers(); + Task GetAllLecturers(); Task Ping(); Task RequestPasswordRecovery(RequestPasswordRecoveryViewModel model); Task ResetPassword(ResetPasswordViewModel model); diff --git a/HwProj.AuthService/HwProj.AuthService.IntegrationTests/AuthServiceTests.cs b/HwProj.AuthService/HwProj.AuthService.IntegrationTests/AuthServiceTests.cs index c77776a48..404e38e43 100644 --- a/HwProj.AuthService/HwProj.AuthService.IntegrationTests/AuthServiceTests.cs +++ b/HwProj.AuthService/HwProj.AuthService.IntegrationTests/AuthServiceTests.cs @@ -35,7 +35,7 @@ private Claim[] ValidateToken(Result resultData) ValidateIssuer = true, ValidateAudience = false, ValidateLifetime = true, - IssuerSigningKey = AuthorizationKey.SecurityKey, + IssuerSigningKey = null, ValidateIssuerSigningKey = true }; var claims = handler.ValidateToken(resultData.Value.AccessToken, validations, out var tokenSecure); @@ -110,15 +110,6 @@ private static AccountDataDto GenerateAccountDataDto(RegisterViewModel model) false, model.MiddleName); - private static User GenerateUser(RegisterViewModel model) - => new User - { - Name = model.Name, - Surname = model.Surname, - MiddleName = model.MiddleName, - IsExternalAuth = false - }; - private IAuthServiceClient _authServiceClient; [SetUp] diff --git a/HwProj.Common/HwProj.Common.Net8/ConnectionString.cs b/HwProj.Common/HwProj.Common.Net8/ConnectionString.cs new file mode 100644 index 000000000..32bc4db97 --- /dev/null +++ b/HwProj.Common/HwProj.Common.Net8/ConnectionString.cs @@ -0,0 +1,16 @@ +using System.Runtime.InteropServices; +using Microsoft.Extensions.Configuration; +using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration; + +namespace HwProj.Common.Net8; + +public static class ConnectionString +{ + public static string GetConnectionString(IConfiguration configuration) + { + var option = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) + ? "DefaultConnectionForLinux" + : "DefaultConnectionForWindows"; + return configuration.GetConnectionString(option) ?? ""; + } +} \ No newline at end of file diff --git a/HwProj.Common/HwProj.Common.Net8/HwProj.Common.Net8.csproj b/HwProj.Common/HwProj.Common.Net8/HwProj.Common.Net8.csproj new file mode 100644 index 000000000..63ae51c26 --- /dev/null +++ b/HwProj.Common/HwProj.Common.Net8/HwProj.Common.Net8.csproj @@ -0,0 +1,14 @@ + + + net8.0 + enable + enable + + + + + + + + + diff --git a/HwProj.Common/HwProj.Common.Net8/StartupExtensions.cs b/HwProj.Common/HwProj.Common.Net8/StartupExtensions.cs new file mode 100644 index 000000000..004a12c0f --- /dev/null +++ b/HwProj.Common/HwProj.Common.Net8/StartupExtensions.cs @@ -0,0 +1,38 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace HwProj.Common.Net8; + +public static class StartupExtensions +{ + public static IApplicationBuilder UseDatabase(this IApplicationBuilder app, IHostEnvironment env, DbContext? context = null) + { + if (context == null) return app; + if (env.IsDevelopment()) + { + context.Database.EnsureCreated(); + return app; + } + + var logger = app.ApplicationServices + .GetService()! + .CreateLogger(typeof(StartupExtensions)); + + var tries = 0; + const int maxTries = 100; + + while (!context.Database.CanConnect() && ++tries <= maxTries) + { + logger.LogWarning($"Can't connect to database. Try {tries}."); + Thread.Sleep(5000); + } + + if (tries > maxTries) throw new Exception("Can't connect to database"); + context.Database.Migrate(); + + return app; + } +} diff --git a/HwProj.Common/HwProj.Models/AuthService/ViewModels/RegisterExpertViewModel.cs b/HwProj.Common/HwProj.Models/AuthService/ViewModels/RegisterExpertViewModel.cs index 34f9f3781..7ff7a0909 100644 --- a/HwProj.Common/HwProj.Models/AuthService/ViewModels/RegisterExpertViewModel.cs +++ b/HwProj.Common/HwProj.Models/AuthService/ViewModels/RegisterExpertViewModel.cs @@ -1,7 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; namespace HwProj.Models.AuthService.ViewModels { diff --git a/HwProj.Common/HwProj.Models/ContentService/Attributes/CorrectFileTypeAttribute.cs b/HwProj.Common/HwProj.Models/ContentService/Attributes/CorrectFileTypeAttribute.cs new file mode 100644 index 000000000..2530197cd --- /dev/null +++ b/HwProj.Common/HwProj.Models/ContentService/Attributes/CorrectFileTypeAttribute.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using Microsoft.AspNetCore.Http; +using FileTypeChecker.Abstracts; +using FileTypeChecker.Types; + +namespace HwProj.Models.ContentService.Attributes +{ + [AttributeUsage(AttributeTargets.Property)] + public class CorrectFileTypeAttribute : FileValidationAttribute + { + private static readonly HashSet ForbiddenFileTypes = new HashSet + { + new MachO(), new Executable(), new ExecutableAndLinkableFormat() + }; + + protected override ValidationResult Validate(IFormFile file) + { + try + { + using var fileContent = file.OpenReadStream(); + //FileTypeValidator.RegisterCustomTypes(typeof(MachO).Assembly); + if ( //!FileTypeValidator.IsTypeRecognizable(fileContent) || + ForbiddenFileTypes.Any(type => type.DoesMatchWith(fileContent))) + { + return new ValidationResult( + $"Файл `{file.FileName}` имеет недопустимый тип ${file.ContentType}"); + } + } + catch + { + return new ValidationResult( + $"Невозможно прочитать файл `{file.FileName}`"); + } + + return ValidationResult.Success; + } + + private class MachO : FileType + { + private const string TypeName = "MacOS executable"; + private const string TypeExtension = "macho"; + + private static readonly byte[][] MagicBytes = + { + new byte[] { 0xfe, 0xed, 0xfa, 0xce }, // Mach-O BE 32-bit + new byte[] { 0xfe, 0xed, 0xfa, 0xcf }, // Mach-O BE 64-bit + new byte[] { 0xce, 0xfa, 0xed, 0xfe }, // Mach-O LE 32-bit + new byte[] { 0xcf, 0xfa, 0xed, 0xfe }, // Mach-O LE 64-bit + }; + + public MachO() : base(TypeName, TypeExtension, MagicBytes) + { + } + } + } +} diff --git a/HwProj.Common/HwProj.Models/ContentService/Attributes/FileValidationAttribute.cs b/HwProj.Common/HwProj.Models/ContentService/Attributes/FileValidationAttribute.cs new file mode 100644 index 000000000..74d725fd8 --- /dev/null +++ b/HwProj.Common/HwProj.Models/ContentService/Attributes/FileValidationAttribute.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using Microsoft.AspNetCore.Http; + +namespace HwProj.Models.ContentService.Attributes +{ + public abstract class FileValidationAttribute : ValidationAttribute + { + protected abstract ValidationResult Validate(IFormFile file); + + protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) => + value switch + { + IFormFile singleFile => Validate(singleFile), + IEnumerable files => files + .Select(Validate) + .FirstOrDefault(x => x != ValidationResult.Success) ?? ValidationResult.Success, + _ => null + }; + } +} diff --git a/HwProj.Common/HwProj.Models/ContentService/Attributes/MaxFileSizeAttribute.cs b/HwProj.Common/HwProj.Models/ContentService/Attributes/MaxFileSizeAttribute.cs index 3e8783afa..2f94eef4e 100644 --- a/HwProj.Common/HwProj.Models/ContentService/Attributes/MaxFileSizeAttribute.cs +++ b/HwProj.Common/HwProj.Models/ContentService/Attributes/MaxFileSizeAttribute.cs @@ -5,27 +5,20 @@ namespace HwProj.Models.ContentService.Attributes { [AttributeUsage(AttributeTargets.Property)] - public class MaxFileSizeAttribute : ValidationAttribute + public class MaxFileSizeAttribute : FileValidationAttribute { private readonly long _maxFileSizeInBytes; public MaxFileSizeAttribute(long maxFileSizeInBytes) - { - _maxFileSizeInBytes = maxFileSizeInBytes; - } + => _maxFileSizeInBytes = maxFileSizeInBytes; - protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) + protected override ValidationResult Validate(IFormFile file) { - if (value is IFormFile file) - { - if (file.Length > _maxFileSizeInBytes) - { - return new ValidationResult( - $"Максимальный размер файла: {_maxFileSizeInBytes / 1024 / 1024} MB."); - } - } + if (file.Length > _maxFileSizeInBytes) + return new ValidationResult( + $"Файл `{file.FileName}` превышает лимит в {_maxFileSizeInBytes / 1024 / 1024} MB"); return ValidationResult.Success; } } -} \ No newline at end of file +} diff --git a/HwProj.Common/HwProj.Models/ContentService/CourseUnitType/CourseUnitType.cs b/HwProj.Common/HwProj.Models/ContentService/CourseUnitType/CourseUnitType.cs new file mode 100644 index 000000000..1561d1b65 --- /dev/null +++ b/HwProj.Common/HwProj.Models/ContentService/CourseUnitType/CourseUnitType.cs @@ -0,0 +1,9 @@ +namespace HwProj.Models.CourseUnitType +{ + public static class CourseUnitType + { + public const string Homework = "Homework"; + public const string Solution = "Solution"; + public const string Task = "Task"; + }; +}; \ No newline at end of file diff --git a/HwProj.Common/HwProj.Models/ContentService/DTO/CourseFilesTransferDTO.cs b/HwProj.Common/HwProj.Models/ContentService/DTO/CourseFilesTransferDTO.cs new file mode 100644 index 000000000..4a4a25ef0 --- /dev/null +++ b/HwProj.Common/HwProj.Models/ContentService/DTO/CourseFilesTransferDTO.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace HwProj.Models.ContentService.DTO +{ + public class CourseFilesTransferDto + { + public long SourceCourseId { get; set; } + public long TargetCourseId { get; set; } + public List HomeworksMapping { get; set; } = new List(); + } +} diff --git a/HwProj.Common/HwProj.Models/ContentService/DTO/FileInfoDTO.cs b/HwProj.Common/HwProj.Models/ContentService/DTO/FileInfoDTO.cs index a39a98b0d..da1aae14d 100644 --- a/HwProj.Common/HwProj.Models/ContentService/DTO/FileInfoDTO.cs +++ b/HwProj.Common/HwProj.Models/ContentService/DTO/FileInfoDTO.cs @@ -2,9 +2,12 @@ namespace HwProj.Models.ContentService.DTO { public class FileInfoDTO { + public long Id { get; set; } public string Name { get; set; } - public long Size { get; set; } - public string Key { get; set; } - public long HomeworkId { get; set; } + public string Status { get; set; } + public long SizeInBytes { get; set; } + + public string CourseUnitType { get; set; } + public long CourseUnitId { get; set; } } } \ No newline at end of file diff --git a/HwProj.Common/HwProj.Models/ContentService/DTO/FileLinkDTO.cs b/HwProj.Common/HwProj.Models/ContentService/DTO/FileLinkDTO.cs new file mode 100644 index 000000000..3cd7cd86c --- /dev/null +++ b/HwProj.Common/HwProj.Models/ContentService/DTO/FileLinkDTO.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace HwProj.Models.ContentService.DTO +{ + + public class FileLinkDTO + { + public string DownloadUrl { get; set; } + public List FileScopes { get; set; } + } +} diff --git a/HwProj.Common/HwProj.Models/ContentService/DTO/ProcessFilesDTO.cs b/HwProj.Common/HwProj.Models/ContentService/DTO/ProcessFilesDTO.cs new file mode 100644 index 000000000..f9d9a16b9 --- /dev/null +++ b/HwProj.Common/HwProj.Models/ContentService/DTO/ProcessFilesDTO.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using HwProj.Models.ContentService.Attributes; +using Microsoft.AspNetCore.Http; + +namespace HwProj.Models.ContentService.DTO +{ + public class ProcessFilesDTO + { + public ScopeDTO FilesScope { get; set; } + + public List DeletingFileIds { get; set; } = new List(); + + [CorrectFileType] + [MaxFileSize(100 * 1024 * 1024)] + public List NewFiles { get; set; } = new List(); + } +} diff --git a/HwProj.Common/HwProj.Models/ContentService/DTO/ScopeDTO.cs b/HwProj.Common/HwProj.Models/ContentService/DTO/ScopeDTO.cs new file mode 100644 index 000000000..ea9d85d45 --- /dev/null +++ b/HwProj.Common/HwProj.Models/ContentService/DTO/ScopeDTO.cs @@ -0,0 +1,9 @@ +namespace HwProj.Models.ContentService.DTO +{ + public class ScopeDTO + { + public long CourseId { get; set; } + public string CourseUnitType { get; set; } + public long CourseUnitId { get; set; } + } +} diff --git a/HwProj.Common/HwProj.Models/ContentService/DTO/ScopeMappingPairDTO.cs b/HwProj.Common/HwProj.Models/ContentService/DTO/ScopeMappingPairDTO.cs new file mode 100644 index 000000000..9604495a8 --- /dev/null +++ b/HwProj.Common/HwProj.Models/ContentService/DTO/ScopeMappingPairDTO.cs @@ -0,0 +1,8 @@ +namespace HwProj.Models.ContentService.DTO +{ + public class ScopeMappingDto + { + public long Source { get; set; } + public long Target { get; set; } + } +} diff --git a/HwProj.Common/HwProj.Models/CoursesService/ViewModels/CourseViewModels.cs b/HwProj.Common/HwProj.Models/CoursesService/ViewModels/CourseViewModels.cs index fbabee91e..18e2b51b6 100644 --- a/HwProj.Common/HwProj.Models/CoursesService/ViewModels/CourseViewModels.cs +++ b/HwProj.Common/HwProj.Models/CoursesService/ViewModels/CourseViewModels.cs @@ -3,6 +3,7 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using HwProj.Models.AuthService.DTO; +using HwProj.Models.CoursesService.DTO; namespace HwProj.Models.CoursesService.ViewModels { @@ -12,12 +13,10 @@ public class CreateCourseViewModel [RegularExpression(@"^\S+.*", ErrorMessage = "Name shouldn't start with white spaces.")] public string Name { get; set; } - public string GroupName { get; set; } - - public List StudentIDs { get; set; } = new List(); - public bool FetchStudents { get; set; } + public List GroupNames { get; set; } = new List(); + public List StudentIDs { get; set; } = new List(); + public bool FetchStudents { get; set; } [Required] public bool IsOpen { get; set; } - public long? BaseCourseId { get; set; } } @@ -59,6 +58,12 @@ public class CourseViewModel public HomeworkViewModel[] Homeworks { get; set; } } + public class CourseAllData + { + public CourseViewModel Course { get; set; } + public MentorToAssignedStudentsDTO[] AssignedStudents { get; set; } + } + // Модель для списка всех курсов public class CoursePreview { diff --git a/HwProj.Common/HwProj.Models/CoursesService/ViewModels/CriterionViewModel.cs b/HwProj.Common/HwProj.Models/CoursesService/ViewModels/CriterionViewModel.cs new file mode 100644 index 000000000..7f07a540a --- /dev/null +++ b/HwProj.Common/HwProj.Models/CoursesService/ViewModels/CriterionViewModel.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace HwProj.Models.CoursesService.ViewModels +{ + public enum CriterionType + { + Free = 0 + } + + public class CriterionViewModel + { + public long Id { get; set; } + public CriterionType Type { get; set; } + [Required] public string Name { get; set; } = null!; + [Range(0, int.MaxValue)] public int MaxPoints { get; set; } + } +} diff --git a/HwProj.Common/HwProj.Models/CoursesService/ViewModels/HomeworkTaskViewModels.cs b/HwProj.Common/HwProj.Models/CoursesService/ViewModels/HomeworkTaskViewModels.cs index 8c40835aa..328d288ad 100644 --- a/HwProj.Common/HwProj.Models/CoursesService/ViewModels/HomeworkTaskViewModels.cs +++ b/HwProj.Common/HwProj.Models/CoursesService/ViewModels/HomeworkTaskViewModels.cs @@ -1,6 +1,7 @@ -using System; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using Newtonsoft.Json; namespace HwProj.Models.CoursesService.ViewModels { @@ -35,6 +36,8 @@ public class HomeworkTaskViewModel public bool IsGroupWork { get; set; } public bool IsDeferred { get; set; } + + public List? Criteria { get; set; } = new List(); } public class HomeworkTaskForEditingViewModel @@ -44,7 +47,7 @@ public class HomeworkTaskForEditingViewModel public HomeworkViewModel Homework { get; set; } } - public class CreateTaskViewModel + public class PostTaskViewModel { [Required] [RegularExpression(@"^\S+.*", ErrorMessage = "Name shouldn't start with white spaces.")] @@ -63,5 +66,7 @@ public class CreateTaskViewModel [Required] public int MaxRating { get; set; } public ActionOptions? ActionOptions { get; set; } + + public List Criteria { get; set; } } } diff --git a/HwProj.Common/HwProj.Models/CoursesService/ViewModels/HomeworkViewModels.cs b/HwProj.Common/HwProj.Models/CoursesService/ViewModels/HomeworkViewModels.cs index 5b5779fd0..2c7b0a857 100644 --- a/HwProj.Common/HwProj.Models/CoursesService/ViewModels/HomeworkViewModels.cs +++ b/HwProj.Common/HwProj.Models/CoursesService/ViewModels/HomeworkViewModels.cs @@ -24,7 +24,7 @@ public class CreateHomeworkViewModel public List Tags { get; set; } = new List(); - public List Tasks { get; set; } = new List(); + public List Tasks { get; set; } = new List(); public ActionOptions? ActionOptions { get; set; } } diff --git a/HwProj.Common/HwProj.Models/CoursesService/ViewModels/QuestionModels.cs b/HwProj.Common/HwProj.Models/CoursesService/ViewModels/QuestionModels.cs index 2d9f871ee..86cfa8195 100644 --- a/HwProj.Common/HwProj.Models/CoursesService/ViewModels/QuestionModels.cs +++ b/HwProj.Common/HwProj.Models/CoursesService/ViewModels/QuestionModels.cs @@ -22,4 +22,11 @@ public class GetTaskQuestionDto public string? Answer { get; set; } public string? LecturerId { get; set; } } + + public class QuestionsSummary + { + public long TaskId { get; set; } + public string TaskTitle { get; set; } + public int Count { get; set; } + } } diff --git a/HwProj.Common/HwProj.Models/HwProj.Models.csproj b/HwProj.Common/HwProj.Models/HwProj.Models.csproj index 6f01185ae..f1514f75f 100644 --- a/HwProj.Common/HwProj.Models/HwProj.Models.csproj +++ b/HwProj.Common/HwProj.Models/HwProj.Models.csproj @@ -1,15 +1,14 @@  - netcoreapp2.2 + netstandard2.0 $(CSharpLanguageVersion) $(NullableReferenceTypes) - - - + + diff --git a/HwProj.Common/HwProj.Models/Roles/Roles.cs b/HwProj.Common/HwProj.Models/Roles/Roles.cs index 72edfe5cc..a78aa84b6 100644 --- a/HwProj.Common/HwProj.Models/Roles/Roles.cs +++ b/HwProj.Common/HwProj.Models/Roles/Roles.cs @@ -1,12 +1,7 @@ -using Microsoft.AspNetCore.Identity; - -namespace HwProj.Models.Roles +namespace HwProj.Models.Roles { public static class Roles { - public static IdentityRole Lecturer = new IdentityRole("Lecturer"); - public static IdentityRole Student = new IdentityRole("Student"); - public static IdentityRole Expert = new IdentityRole("Expert"); public const string LecturerRole = "Lecturer"; public const string StudentRole = "Student"; public const string ExpertRole = "Expert"; diff --git a/HwProj.Common/HwProj.Models/SolutionsService/GetSolutionModel.cs b/HwProj.Common/HwProj.Models/SolutionsService/GetSolutionModel.cs index d61d4e8d1..5e1b09a58 100644 --- a/HwProj.Common/HwProj.Models/SolutionsService/GetSolutionModel.cs +++ b/HwProj.Common/HwProj.Models/SolutionsService/GetSolutionModel.cs @@ -19,6 +19,7 @@ public GetSolutionModel(Solution model, AccountDataDto[]? groupMates, AccountDat ?? Array.Empty(); LecturerComment = model.LecturerComment; PublicationDate = model.PublicationDate; + IsModified = model.IsModified; Rating = model.Rating; StudentId = model.StudentId; TaskId = model.TaskId; @@ -44,6 +45,7 @@ public GetSolutionModel(Solution model, AccountDataDto[]? groupMates, AccountDat public long TaskId { get; set; } public DateTime PublicationDate { get; set; } + public bool IsModified { get; set; } public string LecturerComment { get; set; } diff --git a/HwProj.Common/HwProj.Models/SolutionsService/PostSolutionModel.cs b/HwProj.Common/HwProj.Models/SolutionsService/PostSolutionModel.cs index c8e3246b5..7e1177cbf 100644 --- a/HwProj.Common/HwProj.Models/SolutionsService/PostSolutionModel.cs +++ b/HwProj.Common/HwProj.Models/SolutionsService/PostSolutionModel.cs @@ -4,20 +4,6 @@ namespace HwProj.Models.SolutionsService { public class PostSolutionModel { - public PostSolutionModel(SolutionViewModel model) - { - GithubUrl = model.GithubUrl; - Comment = model.Comment; - StudentId = model.StudentId; - PublicationDate = model.PublicationDate; - LecturerComment = model.LecturerComment; - Rating = model.Rating; - } - - public PostSolutionModel() - { - } - public string GithubUrl { get; set; } public string Comment { get; set; } diff --git a/HwProj.Common/HwProj.Models/SolutionsService/Solution.cs b/HwProj.Common/HwProj.Models/SolutionsService/Solution.cs index 3a41dfeec..a8c720032 100644 --- a/HwProj.Common/HwProj.Models/SolutionsService/Solution.cs +++ b/HwProj.Common/HwProj.Models/SolutionsService/Solution.cs @@ -24,7 +24,8 @@ public class Solution : IEntity public long TaskId { get; set; } public DateTime PublicationDate { get; set; } - + public bool IsModified { get; set; } + public DateTime? RatingDate { get; set; } public string LecturerComment { get; set; } diff --git a/HwProj.Common/HwProj.Repositories.Net8/CrudRepository.cs b/HwProj.Common/HwProj.Repositories.Net8/CrudRepository.cs new file mode 100644 index 000000000..68f29cbc1 --- /dev/null +++ b/HwProj.Common/HwProj.Repositories.Net8/CrudRepository.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Z.EntityFramework.Plus; + +namespace HwProj.Repositories.Net8; + +public class CrudRepository(DbContext context) : ICrudRepository + where TEntity : class, IEntity + where TKey : IEquatable +{ + protected DbContext Context => context; + + public async Task AddAsync(TEntity item) + { + await context.AddAsync(item); + await context.SaveChangesAsync(); + return item.Id; + } + + public async Task> AddRangeAsync(IEnumerable items) + { + items = items.ToList(); + await context.AddRangeAsync(items); + await context.SaveChangesAsync(); + return items.Select(item => item.Id).ToList(); + } + + public async Task DeleteAsync(TKey id) + { + await context.Set() + .Where(entity => entity.Id.Equals(id)) + .DeleteAsync() + ; + } + + public async Task UpdateAsync(TKey id, Expression> updateFactory) + { + await context.Set() + .Where(entity => entity.Id.Equals(id)) + .UpdateAsync(updateFactory) + ; + } + + public IQueryable GetAll() + { + return context.Set().AsNoTracking(); + } + + public IQueryable FindAll(Expression> predicate) + { + return context.Set().AsNoTracking().Where(predicate); + } + + public async Task GetAsync(TKey id) + { + return await context.FindAsync(id); + } + + public async Task FindAsync(Expression> predicate) + { + return await context.Set().AsNoTracking().FirstOrDefaultAsync(predicate); + } +} diff --git a/HwProj.Common/HwProj.Repositories.Net8/HwProj.Repositories.Net8.csproj b/HwProj.Common/HwProj.Repositories.Net8/HwProj.Repositories.Net8.csproj new file mode 100644 index 000000000..07c4efcd8 --- /dev/null +++ b/HwProj.Common/HwProj.Repositories.Net8/HwProj.Repositories.Net8.csproj @@ -0,0 +1,11 @@ + + + net8.0 + 12 + disable + + + + + + diff --git a/HwProj.Common/HwProj.Repositories.Net8/ICrudRepository.cs b/HwProj.Common/HwProj.Repositories.Net8/ICrudRepository.cs new file mode 100644 index 000000000..3323efcd3 --- /dev/null +++ b/HwProj.Common/HwProj.Repositories.Net8/ICrudRepository.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; + +namespace HwProj.Repositories.Net8; + +public interface ICrudRepository + where TEntity : IEntity + where TKey : IEquatable +{ + Task AddAsync(TEntity item); + Task> AddRangeAsync(IEnumerable items); + Task DeleteAsync(TKey id); + Task UpdateAsync(TKey id, Expression> updateFactory); + IQueryable GetAll(); + IQueryable FindAll(Expression> predicate); + Task GetAsync(TKey id); + Task FindAsync(Expression> predicate); +} diff --git a/HwProj.Common/HwProj.Repositories.Net8/IEntity.cs b/HwProj.Common/HwProj.Repositories.Net8/IEntity.cs new file mode 100644 index 000000000..875ce06bf --- /dev/null +++ b/HwProj.Common/HwProj.Repositories.Net8/IEntity.cs @@ -0,0 +1,9 @@ +using System; + +namespace HwProj.Repositories.Net8; + +public interface IEntity + where TKey : IEquatable +{ + TKey Id { get; set; } +} diff --git a/HwProj.Common/HwProj.Repositories/CrudRepository.cs b/HwProj.Common/HwProj.Repositories/CrudRepository.cs index 32b31c016..ea23293b2 100644 --- a/HwProj.Common/HwProj.Repositories/CrudRepository.cs +++ b/HwProj.Common/HwProj.Repositories/CrudRepository.cs @@ -9,7 +9,7 @@ namespace HwProj.Repositories { public class CrudRepository : ReadOnlyRepository, ICrudRepository - where TEntity : class, IEntity, new() + where TEntity : class, IEntity where TKey : IEquatable { public CrudRepository(DbContext context) diff --git a/HwProj.Common/HwProj.Repositories/HwProj.Repositories.csproj b/HwProj.Common/HwProj.Repositories/HwProj.Repositories.csproj index 7c840a1cf..2cbd043ea 100644 --- a/HwProj.Common/HwProj.Repositories/HwProj.Repositories.csproj +++ b/HwProj.Common/HwProj.Repositories/HwProj.Repositories.csproj @@ -1,6 +1,6 @@  - netcoreapp2.1 + netstandard2.0 $(CSharpLanguageVersion) $(NullableReferenceTypes) diff --git a/HwProj.Common/HwProj.Repositories/ReadOnlyRepository.cs b/HwProj.Common/HwProj.Repositories/ReadOnlyRepository.cs index 59c94c59e..568c65bde 100644 --- a/HwProj.Common/HwProj.Repositories/ReadOnlyRepository.cs +++ b/HwProj.Common/HwProj.Repositories/ReadOnlyRepository.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; diff --git a/HwProj.Common/HwProj.Utils/Auth/AuthExtensions.cs b/HwProj.Common/HwProj.Utils/Auth/AuthExtensions.cs index 1a24efbc7..fde5ca45a 100644 --- a/HwProj.Common/HwProj.Utils/Auth/AuthExtensions.cs +++ b/HwProj.Common/HwProj.Utils/Auth/AuthExtensions.cs @@ -1,9 +1,6 @@ using System.Linq; -using HwProj.Models.AuthService.DTO; -using HwProj.Models.AuthService.ViewModels; using HwProj.Models.Roles; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Primitives; namespace HwProj.Utils.Authorization { @@ -12,21 +9,6 @@ public static class AuthExtensions public static string? GetUserIdFromHeader(this HttpRequest request) => request.Headers.TryGetValue("UserId", out var id) ? id.FirstOrDefault() : null; - public static AccountDataDto ToAccountDataDto(this User user, string role) - { - return new AccountDataDto( - user.Id, - user.Name, - user.Surname, - user.Email, - role, - user.IsExternalAuth, - user.MiddleName, - user.GitHubId, - user.CompanyName, - user.Bio); - } - public static string GetUserName(this HttpRequest request) { return request.Query.First(x => x.Key == "_userName").Value.ToString(); @@ -45,13 +27,5 @@ public static bool IsLecturer(this string role) { return role == Roles.LecturerRole; } - - public static string GetMentorId(this HttpRequest request) - { - request.HttpContext.Request.Headers.TryGetValue("UserId", out var userId); - return StringValues.IsNullOrEmpty(userId) - ? null - : userId.ToString(); - } } } diff --git a/HwProj.Common/HwProj.Utils/Configuration/StartupExtensions.cs b/HwProj.Common/HwProj.Utils/Configuration/StartupExtensions.cs index 01c8b97db..920b10f97 100644 --- a/HwProj.Common/HwProj.Utils/Configuration/StartupExtensions.cs +++ b/HwProj.Common/HwProj.Utils/Configuration/StartupExtensions.cs @@ -1,28 +1,17 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Net.Sockets; using System.Threading; using AutoMapper; -using HwProj.EventBus.Client; -using HwProj.EventBus.Client.Implementations; -using HwProj.EventBus.Client.Interfaces; using HwProj.Utils.Auth; using HwProj.Utils.Configuration.Middleware; -using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using Newtonsoft.Json; -using Polly; -using RabbitMQ.Client; -using RabbitMQ.Client.Exceptions; namespace HwProj.Utils.Configuration { @@ -38,30 +27,7 @@ public static IServiceCollection ConfigureHwProjServices(this IServiceCollection .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.ConfigureHwProjServiceSwaggerGen(serviceName); - if (serviceName != "AuthService API") - { - services.AddAuthentication(options => - { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - }) - .AddJwtBearer(x => - { - x.RequireHttpsMetadata = false; //TODO: dev env setting - x.TokenValidationParameters = new TokenValidationParameters - { - ValidIssuer = "AuthService", - ValidateIssuer = true, - ValidateAudience = false, - ValidateLifetime = true, - IssuerSigningKey = AuthorizationKey.SecurityKey, - ValidateIssuerSigningKey = true - }; - }); - } - services.AddTransient(); - services.AddHttpContextAccessor(); return services; @@ -106,48 +72,6 @@ private static void ConfigureHwProjServiceSwaggerGen(this IServiceCollection ser }); } - public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration) - { - var eventBusSection = configuration.GetSection("EventBus"); - - var retryCount = 5; - if (!string.IsNullOrEmpty(eventBusSection["EventBusRetryCount"])) - { - retryCount = int.Parse(eventBusSection["EventBusRetryCount"]); - } - - services.AddSingleton(sp => Policy.Handle() - .Or() - .WaitAndRetry(retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))); - - services.AddSingleton(sp => new ConnectionFactory - { - HostName = eventBusSection["EventBusHostName"], - UserName = eventBusSection["EventBusUserName"], - Password = eventBusSection["EventBusPassword"], - VirtualHost = eventBusSection["EventBusVirtualHost"] - }); - - services.AddSingleton(); - services.AddSingleton(); - - var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes()).ToList(); - var eventTypes = types.Where(x => typeof(Event).IsAssignableFrom(x)); - foreach (var eventType in eventTypes) - { - var fullTypeInterface = typeof(IEventHandler<>).MakeGenericType(eventType); - var handlersTypes = types.Where(x => - fullTypeInterface.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract); - - foreach (var handlerType in handlersTypes) - { - services.AddTransient(handlerType); - } - } - - return services; - } - public static IApplicationBuilder ConfigureHwProj(this IApplicationBuilder app, IHostingEnvironment env, string serviceName, DbContext? context = null) { diff --git a/HwProj.ContentService/HwProj.ContentService.API/Configuration/ExternalStorageConfiguration.cs b/HwProj.ContentService/HwProj.ContentService.API/Configuration/ExternalStorageConfiguration.cs new file mode 100644 index 000000000..7712a69c9 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Configuration/ExternalStorageConfiguration.cs @@ -0,0 +1,10 @@ +namespace HwProj.ContentService.API.Configuration; + +public class ExternalStorageConfiguration +{ + public string? AccessKeyId { get; set; } + public string? SecretKey { get; set; } + public string? Region { get; set; } + public string? ServiceURL { get; set; } + public string? DefaultBucketName { get; set; } +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Configuration/LocalStorageConfiguration.cs b/HwProj.ContentService/HwProj.ContentService.API/Configuration/LocalStorageConfiguration.cs new file mode 100644 index 000000000..6719221e1 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Configuration/LocalStorageConfiguration.cs @@ -0,0 +1,6 @@ +namespace HwProj.ContentService.API.Configuration; + +public class LocalStorageConfiguration +{ + public string? Path { get; set; } +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Controllers/FilesController.cs b/HwProj.ContentService/HwProj.ContentService.API/Controllers/FilesController.cs index de3ef1761..85b0db5c5 100644 --- a/HwProj.ContentService/HwProj.ContentService.API/Controllers/FilesController.cs +++ b/HwProj.ContentService/HwProj.ContentService.API/Controllers/FilesController.cs @@ -1,5 +1,10 @@ -using HwProj.ContentService.API.Services; +using System.Net; +using HwProj.ContentService.API.Extensions; +using HwProj.ContentService.API.Models.Enums; +using HwProj.ContentService.API.Models.Messages; +using HwProj.ContentService.API.Services.Interfaces; using HwProj.Models.ContentService.DTO; +using HwProj.Models.Result; using HwProj.Utils.Authorization; using Microsoft.AspNetCore.Mvc; @@ -9,40 +14,113 @@ namespace HwProj.ContentService.API.Controllers; [Route("api/[controller]")] public class FilesController : ControllerBase { - private readonly IFilesService _filesService; + private readonly IS3FilesService _s3FilesService; + private readonly IMessageProducer _messageProducer; + private readonly IFilesInfoService _filesInfoService; + private readonly ILocalFilesService _localFilesService; + private readonly IFileKeyService _fileKeyService; + private readonly ILogger _logger; - public FilesController(IFilesService filesService) + public FilesController(IS3FilesService s3FilesService, IMessageProducer messageProducer, + IFilesInfoService filesInfoService, ILocalFilesService localFilesService, ILogger logger, + IFileKeyService fileKeyService) { - _filesService = filesService; + _s3FilesService = s3FilesService; + _messageProducer = messageProducer; + _filesInfoService = filesInfoService; + _localFilesService = localFilesService; + _logger = logger; + _fileKeyService = fileKeyService; } - [HttpPost("upload")] - public async Task Upload([FromForm] UploadFileDTO uploadFileDto) + [HttpPost("process")] + [ProducesResponseType((int)HttpStatusCode.OK)] + public async Task Process([FromForm] ProcessFilesDTO processFilesDto) { var userId = Request.GetUserIdFromHeader(); - var result = await _filesService.UploadFileAsync(uploadFileDto, userId); - return Ok(result); + var scope = processFilesDto.FilesScope.ToScope(); + + if (processFilesDto.DeletingFileIds.Count > 0) + await _messageProducer.PushDeleteFilesMessages(scope, processFilesDto.DeletingFileIds, userId); + + if (processFilesDto.NewFiles.Count > 0) + { + var uploadFilesMessages = new List(); + foreach (var newFormFile in processFilesDto.NewFiles) + { + // Сохраняем файл локально + var localFilePath = _fileKeyService.BuildServerFilePath(scope, newFormFile.FileName); + await _localFilesService.SaveFile(newFormFile.OpenReadStream(), localFilePath); + _logger.LogInformation("Файл {FileName} успешно сохранён в локальное хранилище по пути {localFilePath}", + newFormFile.FileName, localFilePath); + + var message = new UploadFileMessage( + Scope: processFilesDto.FilesScope.ToScope(), + LocalFilePath: localFilePath, + ContentType: newFormFile.ContentType, + OriginalName: newFormFile.FileName, + SizeInBytes: newFormFile.Length, + SenderId: userId + ); + uploadFilesMessages.Add(message); + } + + await _messageProducer.PushUploadFilesMessages(uploadFilesMessages); + } + + return Ok(); } - + + [HttpPost("statuses")] + [ProducesResponseType(typeof(List), (int)HttpStatusCode.OK)] + public async Task GetStatuses(ScopeDTO scopeDto) + { + var scope = scopeDto.ToScope(); + var filesStatuses = await _filesInfoService.GetFilesStatusesAsync(scope); + return Ok(filesStatuses); + } + [HttpGet("downloadLink")] - public async Task GetDownloadLink([FromQuery] string key) + [ProducesResponseType(typeof(FileLinkDTO[]), (int)HttpStatusCode.OK)] + public async Task GetDownloadLink([FromQuery] long fileId) { - var downloadUrlResult = await _filesService.GetDownloadUrl(key); - return Ok(downloadUrlResult); + var externalKey = await _filesInfoService.GetFileExternalKeyAsync(fileId); + if (externalKey is null) return Ok(Result.Failed("Файл не найден")); + + var fileScopes = await _filesInfoService.GetFileScopesAsync(fileId); + if (fileScopes is null) return Ok(Result.Failed("Файл не найден")); + + var downloadUrl = await _s3FilesService.GetDownloadUrl(externalKey); + if (!downloadUrl.Succeeded) return Ok(Result.Failed(downloadUrl.Errors)); + + var result = new FileLinkDTO + { + DownloadUrl = downloadUrl.Value, + FileScopes = fileScopes.Select(fs => fs.ToScopeDTO()).ToList() + }; + + return Ok(result); } - - [HttpGet("filesInfo/{courseId}")] - public async Task GetFilesInfo(long courseId, [FromQuery] long? homeworkId = null) + + [HttpGet("info/course/{courseId}")] + [ProducesResponseType(typeof(FileInfoDTO[]), (int)HttpStatusCode.OK)] + public async Task GetFilesInfo(long courseId, bool uploadedOnly, string courseUnitType) { - var filesInfo = await _filesService.GetFilesInfoAsync(courseId, homeworkId ?? -1); + if (!Enum.TryParse(courseUnitType, out var unitType)) + return BadRequest("Неожиданный CourseUnitType: " + courseUnitType); + + var filesInfo = await _filesInfoService.GetFilesInfoAsync( + courseId, + uploadedOnly ? FileStatus.ReadyToUse : null, + unitType); return Ok(filesInfo); } - - [HttpDelete] - public async Task DeleteFile([FromQuery] string key) + + [HttpPost("transfer")] + [ProducesResponseType((int)HttpStatusCode.OK)] + public async Task TransferFilesFromCourse(CourseFilesTransferDto filesTransferDto) { - var userId = Request.GetUserIdFromHeader(); - var filesInfo = await _filesService.DeleteFileAsync(key, userId); - return Ok(filesInfo); + await _filesInfoService.TransferFilesFromCourse(filesTransferDto); + return Ok(); } -} \ No newline at end of file +} diff --git a/HwProj.ContentService/HwProj.ContentService.API/Controllers/SystemController.cs b/HwProj.ContentService/HwProj.ContentService.API/Controllers/SystemController.cs new file mode 100644 index 000000000..9b60d7333 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Controllers/SystemController.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Mvc; + +namespace HwProj.ContentService.API.Controllers; + +[Route("api/[controller]")] +[ApiController] +public class SystemController : ControllerBase +{ + [HttpGet("status")] + public IActionResult Status() => Ok(); +} diff --git a/HwProj.ContentService/HwProj.ContentService.API/Extensions/AmazonS3Extensions.cs b/HwProj.ContentService/HwProj.ContentService.API/Extensions/AmazonS3Extensions.cs index 1ba6794b6..1d2dbe162 100644 --- a/HwProj.ContentService/HwProj.ContentService.API/Extensions/AmazonS3Extensions.cs +++ b/HwProj.ContentService/HwProj.ContentService.API/Extensions/AmazonS3Extensions.cs @@ -1,29 +1,9 @@ using Amazon.Runtime; -using Amazon.S3; -using Amazon.S3.Util; namespace HwProj.ContentService.API.Extensions; public static class AmazonS3Extensions { - public static async Task CreateBucketIfNotExists(this IAmazonS3 amazonS3Client, string bucketName) - { - if (!await AmazonS3Util.DoesS3BucketExistV2Async(amazonS3Client, bucketName)) - { - try - { - await amazonS3Client.PutBucketAsync(bucketName); - } - catch (AmazonS3Exception exception) - { - var errorMessage = $"Не удалось создать бакет для хранения данных {bucketName}. " + - $"Код ошибки: {exception.ErrorCode}. " + - $"Сообщение: {exception.Message}"; - throw new ApplicationException(errorMessage, exception); - } - } - } - public static bool IsSuccessStatusCode(this AmazonWebServiceResponse response) => (int)response.HttpStatusCode >= 200 && (int)response.HttpStatusCode < 300; } \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Extensions/ConfigurationExtensions.cs b/HwProj.ContentService/HwProj.ContentService.API/Extensions/ConfigurationExtensions.cs index ec7e0e24a..f332e4e8d 100644 --- a/HwProj.ContentService/HwProj.ContentService.API/Extensions/ConfigurationExtensions.cs +++ b/HwProj.ContentService/HwProj.ContentService.API/Extensions/ConfigurationExtensions.cs @@ -1,14 +1,17 @@ +using System.Threading.Channels; using Amazon; using Amazon.Extensions.NETCore.Setup; using Amazon.Runtime; using Amazon.S3; using HwProj.ContentService.API.Configuration; +using HwProj.ContentService.API.Models.Database; +using HwProj.ContentService.API.Models.Messages; +using HwProj.ContentService.API.Repositories; using HwProj.ContentService.API.Services; -using HwProj.Utils.Auth; -using HwProj.Utils.Configuration.Middleware; -using Microsoft.AspNetCore.Authentication.JwtBearer; +using HwProj.ContentService.API.Services.Interfaces; +using HwProj.Utils.Configuration; using Microsoft.AspNetCore.Http.Features; -using Microsoft.IdentityModel.Tokens; +using Microsoft.EntityFrameworkCore; using Microsoft.OpenApi.Models; using Newtonsoft.Json; @@ -16,11 +19,16 @@ namespace HwProj.ContentService.API.Extensions; public static class ConfigurationExtensions { - public static IServiceCollection ConfigureWithAWS(this IServiceCollection services, + public static IServiceCollection ConfigureWithAWS(this IServiceCollection services, IHostEnvironment env, IConfigurationRoot configuration) { - var clientConfigurationSection = configuration.GetSection("StorageClientConfiguration"); - services.Configure(clientConfigurationSection); + // Достаем конфигурацию удаленного хранилища + var externalStorageSection = configuration.GetSection("ExternalStorageConfiguration"); + services.Configure(externalStorageSection); + + // Достаем конфигурацию локального хранилища для временного хранения файлов + var localStorageSection = configuration.GetSection("LocalStorageConfiguration"); + services.Configure(localStorageSection); // Увеличиваем допустимый размер тела запросов, содержащих multipart/form-data services.Configure(options => @@ -28,9 +36,30 @@ public static IServiceCollection ConfigureWithAWS(this IServiceCollection servic options.MultipartBodyLengthLimit = 200 * 1024 * 1024; }); - services.ConfigureStorageClient(clientConfigurationSection); + // Подготавливаем инфраструктуру БД + var connectionString = ConnectionString.GetConnectionString(configuration); + services.AddDbContext(options => options.UseSqlServer(connectionString)); + services.AddScoped(); + + if (env.IsDevelopment()) + { + services.AddSingleton(); + } + else + { + services.ConfigureExternalStorageClient(externalStorageSection); + services.AddSingleton(); + } + + services.ConfigureChannelInfrastructure(); + + // Регистрируем как синглтоны, чтобы использовать в MessageConsumer services.AddSingleton(); - services.AddScoped(); + + services.AddSingleton(); + + services.AddScoped(); + services.AddScoped(); services.AddHttpClient(); @@ -38,9 +67,29 @@ public static IServiceCollection ConfigureWithAWS(this IServiceCollection servic return services; } - private static void ConfigureStorageClient(this IServiceCollection services, IConfigurationSection configuration) + private static void ConfigureChannelInfrastructure(this IServiceCollection services) + { + services.AddSingleton>(_ => + Channel.CreateUnbounded( + new UnboundedChannelOptions + { + SingleWriter = false, + SingleReader = true // Один читатель, последовательно работающий с БД + })); + + services.AddSingleton>(serviceProvider => + serviceProvider.GetRequiredService>().Writer); + services.AddSingleton>(serviceProvider => + serviceProvider.GetRequiredService>().Reader); + + // Регистрируем как синглтон, чтобы использовать в MessageConsumer + services.AddSingleton(); + services.AddHostedService(); + } + + private static void ConfigureExternalStorageClient(this IServiceCollection services, IConfigurationSection configuration) { - var clientConfiguration = configuration.Get(); + var clientConfiguration = configuration.Get(); if (clientConfiguration == null) throw new NullReferenceException("Ошибка при чтении конфигурации StorageClientConfiguration"); @@ -68,9 +117,6 @@ private static void ConfigureHwProjContentService(this IServiceCollection servic options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; }); services.ConfigureContentServiceSwaggerGen(); - services.ConfigureContentServiceAuthentication(); - - services.AddTransient(); services.AddHttpContextAccessor(); } @@ -87,26 +133,4 @@ private static void ConfigureContentServiceSwaggerGen(this IServiceCollection se }); }); } - - private static void ConfigureContentServiceAuthentication(this IServiceCollection services) - { - services.AddAuthentication(options => - { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - }) - .AddJwtBearer(x => - { - x.RequireHttpsMetadata = false; //TODO: dev env setting - x.TokenValidationParameters = new TokenValidationParameters - { - ValidIssuer = "AuthService", - ValidateIssuer = true, - ValidateAudience = false, - ValidateLifetime = true, - IssuerSigningKey = AuthorizationKey.SecurityKey, - ValidateIssuerSigningKey = true - }; - }); - } } \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Extensions/MappingExtensions.cs b/HwProj.ContentService/HwProj.ContentService.API/Extensions/MappingExtensions.cs new file mode 100644 index 000000000..6ad412f28 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Extensions/MappingExtensions.cs @@ -0,0 +1,31 @@ +using HwProj.ContentService.API.Models; +using HwProj.ContentService.API.Models.Database; +using HwProj.ContentService.API.Models.Enums; +using HwProj.Models.ContentService.DTO; + +namespace HwProj.ContentService.API.Extensions; + +public static class MappingExtensions +{ + public static Scope ToScope(this FileToCourseUnit fileToCourseUnit) + => new Scope( + CourseId: fileToCourseUnit.CourseId, + CourseUnitId: fileToCourseUnit.CourseUnitId, + CourseUnitType: fileToCourseUnit.CourseUnitType + ); + + public static Scope ToScope(this ScopeDTO scopeDTO) + => new Scope( + CourseId: scopeDTO.CourseId, + CourseUnitType: Enum.Parse(scopeDTO.CourseUnitType), + CourseUnitId: scopeDTO.CourseUnitId + ); + + public static ScopeDTO ToScopeDTO(this Scope scope) + => new ScopeDTO + { + CourseId = scope.CourseId, + CourseUnitType = scope.CourseUnitType.ToString(), + CourseUnitId = scope.CourseUnitId + }; +} diff --git a/HwProj.ContentService/HwProj.ContentService.API/Extensions/WebApplicationExtensions.cs b/HwProj.ContentService/HwProj.ContentService.API/Extensions/WebApplicationExtensions.cs index edd715369..c6a6bde54 100644 --- a/HwProj.ContentService/HwProj.ContentService.API/Extensions/WebApplicationExtensions.cs +++ b/HwProj.ContentService/HwProj.ContentService.API/Extensions/WebApplicationExtensions.cs @@ -1,12 +1,15 @@ using Amazon.S3; +using Amazon.S3.Util; using HwProj.ContentService.API.Configuration; +using HwProj.ContentService.API.Models.Database; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; namespace HwProj.ContentService.API.Extensions; -public static class ConfigureWebApplication +public static class WebApplicationExtensions { - public static WebApplication ConfigureWebApplicationParameters(this WebApplication application) + public static WebApplication ConfigureWebApp(this WebApplication application) { if (application.Environment.IsDevelopment()) { @@ -28,15 +31,16 @@ public static WebApplication ConfigureWebApplicationParameters(this WebApplicati application.UseRouting(); application.MapControllers(); + application.MigrateDatabase(); return application; } - + public static async Task CreateBucketIfNotExists(this WebApplication application) { using var scope = application.Services.CreateScope(); var amazonS3Client = scope.ServiceProvider.GetService(); - var defaultBucketName = scope.ServiceProvider.GetRequiredService>() + var defaultBucketName = scope.ServiceProvider.GetRequiredService>() .Value .DefaultBucketName; if (amazonS3Client == null || defaultBucketName == null) @@ -44,6 +48,44 @@ public static async Task CreateBucketIfNotExists(this WebApplication application throw new ApplicationException("Конфигурация клиента AWS S3 не задана"); } - await amazonS3Client.CreateBucketIfNotExists(defaultBucketName); + try + { + if (!await AmazonS3Util.DoesS3BucketExistV2Async(amazonS3Client, defaultBucketName)) + await amazonS3Client.PutBucketAsync(defaultBucketName); + application.Logger.LogInformation("Сервис успешно запущен. Установлено соединение с YandexObjectStorage"); + } + catch (AmazonS3Exception) + { + application.Logger.LogWarning("Не удалось установить соединение с Yandex Object Storage. " + + "Проверьте значения секции StorageClientConfiguration и перезапустите сервис"); + } + } + + private static void MigrateDatabase(this WebApplication application) + { + using var scope = application.Services.CreateScope(); + var contentContext = scope.ServiceProvider.GetRequiredService(); + + if (application.Environment.IsDevelopment()) + { + contentContext.Database.Migrate(); + return; + } + + var logger = application.Services + .GetRequiredService() + .CreateLogger(typeof(WebApplicationExtensions)); + + var tries = 0; + const int maxTries = 100; + + while (!contentContext.Database.CanConnect() && ++tries <= maxTries) + { + logger.LogWarning($"Can't connect to database. Try {tries}."); + Thread.Sleep(5000); + } + + if (tries > maxTries) throw new Exception("Can't connect to database"); + contentContext.Database.Migrate(); } } \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/HwProj.ContentService.API.csproj b/HwProj.ContentService/HwProj.ContentService.API/HwProj.ContentService.API.csproj index 71fa39b7d..6b7af8f7a 100644 --- a/HwProj.ContentService/HwProj.ContentService.API/HwProj.ContentService.API.csproj +++ b/HwProj.ContentService/HwProj.ContentService.API/HwProj.ContentService.API.csproj @@ -10,15 +10,23 @@ + + - + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + - - + diff --git a/HwProj.ContentService/HwProj.ContentService.API/Migrations/20250511214729_AddFileRecordsTable.Designer.cs b/HwProj.ContentService/HwProj.ContentService.API/Migrations/20250511214729_AddFileRecordsTable.Designer.cs new file mode 100644 index 000000000..20682bb0e --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Migrations/20250511214729_AddFileRecordsTable.Designer.cs @@ -0,0 +1,67 @@ +// +using HwProj.ContentService.API.Models.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace HwProj.ContentService.API.Migrations +{ + [DbContext(typeof(ContentContext))] + [Migration("20250511214729_AddFileRecordsTable")] + partial class AddFileRecordsTable + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("HwProj.ContentService.API.Models.Database.FileRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExternalKey") + .HasColumnType("nvarchar(max)"); + + b.Property("LocalPath") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReferenceCount") + .HasColumnType("int"); + + b.Property("SizeInBytes") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Status"); + + b.ToTable("FileRecords"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/HwProj.ContentService/HwProj.ContentService.API/Migrations/20250511214729_AddFileRecordsTable.cs b/HwProj.ContentService/HwProj.ContentService.API/Migrations/20250511214729_AddFileRecordsTable.cs new file mode 100644 index 000000000..fe6949f4d --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Migrations/20250511214729_AddFileRecordsTable.cs @@ -0,0 +1,45 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace HwProj.ContentService.API.Migrations +{ + /// + public partial class AddFileRecordsTable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "FileRecords", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Status = table.Column(type: "int", nullable: false), + OriginalName = table.Column(type: "nvarchar(max)", nullable: false), + LocalPath = table.Column(type: "nvarchar(max)", nullable: true), + ExternalKey = table.Column(type: "nvarchar(max)", nullable: true), + SizeInBytes = table.Column(type: "bigint", nullable: false), + ContentType = table.Column(type: "nvarchar(max)", nullable: false), + ReferenceCount = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_FileRecords", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_FileRecords_Status", + table: "FileRecords", + column: "Status"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "FileRecords"); + } + } +} diff --git a/HwProj.ContentService/HwProj.ContentService.API/Migrations/20250511214851_AddFileToCourseUnitsTable.Designer.cs b/HwProj.ContentService/HwProj.ContentService.API/Migrations/20250511214851_AddFileToCourseUnitsTable.Designer.cs new file mode 100644 index 000000000..df2a3580e --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Migrations/20250511214851_AddFileToCourseUnitsTable.Designer.cs @@ -0,0 +1,101 @@ +// +using HwProj.ContentService.API.Models.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace HwProj.ContentService.API.Migrations +{ + [DbContext(typeof(ContentContext))] + [Migration("20250511214851_AddFileToCourseUnitsTable")] + partial class AddFileToCourseUnitsTable + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("HwProj.ContentService.API.Models.Database.FileRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExternalKey") + .HasColumnType("nvarchar(max)"); + + b.Property("LocalPath") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReferenceCount") + .HasColumnType("int"); + + b.Property("SizeInBytes") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Status"); + + b.ToTable("FileRecords"); + }); + + modelBuilder.Entity("HwProj.ContentService.API.Models.Database.FileToCourseUnit", b => + { + b.Property("FileRecordId") + .HasColumnType("bigint"); + + b.Property("CourseUnitType") + .HasColumnType("int"); + + b.Property("CourseUnitId") + .HasColumnType("bigint"); + + b.Property("CourseId") + .HasColumnType("bigint"); + + b.HasKey("FileRecordId", "CourseUnitType", "CourseUnitId"); + + b.HasIndex("CourseId"); + + b.HasIndex("FileRecordId"); + + b.ToTable("FileToCourseUnits"); + }); + + modelBuilder.Entity("HwProj.ContentService.API.Models.Database.FileToCourseUnit", b => + { + b.HasOne("HwProj.ContentService.API.Models.Database.FileRecord", "FileRecord") + .WithMany() + .HasForeignKey("FileRecordId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FileRecord"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/HwProj.ContentService/HwProj.ContentService.API/Migrations/20250511214851_AddFileToCourseUnitsTable.cs b/HwProj.ContentService/HwProj.ContentService.API/Migrations/20250511214851_AddFileToCourseUnitsTable.cs new file mode 100644 index 000000000..bded2b246 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Migrations/20250511214851_AddFileToCourseUnitsTable.cs @@ -0,0 +1,51 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace HwProj.ContentService.API.Migrations +{ + /// + public partial class AddFileToCourseUnitsTable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "FileToCourseUnits", + columns: table => new + { + FileRecordId = table.Column(type: "bigint", nullable: false), + CourseUnitId = table.Column(type: "bigint", nullable: false), + CourseUnitType = table.Column(type: "int", nullable: false), + CourseId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_FileToCourseUnits", x => new { x.FileRecordId, x.CourseUnitType, x.CourseUnitId }); + table.ForeignKey( + name: "FK_FileToCourseUnits_FileRecords_FileRecordId", + column: x => x.FileRecordId, + principalTable: "FileRecords", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_FileToCourseUnits_CourseId", + table: "FileToCourseUnits", + column: "CourseId"); + + migrationBuilder.CreateIndex( + name: "IX_FileToCourseUnits_FileRecordId", + table: "FileToCourseUnits", + column: "FileRecordId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "FileToCourseUnits"); + } + } +} diff --git a/HwProj.ContentService/HwProj.ContentService.API/Migrations/ContentContextModelSnapshot.cs b/HwProj.ContentService/HwProj.ContentService.API/Migrations/ContentContextModelSnapshot.cs new file mode 100644 index 000000000..0916dc193 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Migrations/ContentContextModelSnapshot.cs @@ -0,0 +1,98 @@ +// +using HwProj.ContentService.API.Models.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace HwProj.ContentService.API.Migrations +{ + [DbContext(typeof(ContentContext))] + partial class ContentContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("HwProj.ContentService.API.Models.Database.FileRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExternalKey") + .HasColumnType("nvarchar(max)"); + + b.Property("LocalPath") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReferenceCount") + .HasColumnType("int"); + + b.Property("SizeInBytes") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Status"); + + b.ToTable("FileRecords"); + }); + + modelBuilder.Entity("HwProj.ContentService.API.Models.Database.FileToCourseUnit", b => + { + b.Property("FileRecordId") + .HasColumnType("bigint"); + + b.Property("CourseUnitType") + .HasColumnType("int"); + + b.Property("CourseUnitId") + .HasColumnType("bigint"); + + b.Property("CourseId") + .HasColumnType("bigint"); + + b.HasKey("FileRecordId", "CourseUnitType", "CourseUnitId"); + + b.HasIndex("CourseId"); + + b.HasIndex("FileRecordId"); + + b.ToTable("FileToCourseUnits"); + }); + + modelBuilder.Entity("HwProj.ContentService.API.Models.Database.FileToCourseUnit", b => + { + b.HasOne("HwProj.ContentService.API.Models.Database.FileRecord", "FileRecord") + .WithMany() + .HasForeignKey("FileRecordId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FileRecord"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/HwProj.ContentService/HwProj.ContentService.API/Models/DTO/FileTransferDTO.cs b/HwProj.ContentService/HwProj.ContentService.API/Models/DTO/FileTransferDTO.cs new file mode 100644 index 000000000..304640548 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Models/DTO/FileTransferDTO.cs @@ -0,0 +1,13 @@ +using HwProj.ContentService.API.Models.Enums; + +namespace HwProj.ContentService.API.Models.DTO; + +public record FileTransferDTO( + string Name, + long SizeInBytes, + string ContentType, + Stream FileStream, + CourseUnitType CourseUnitType, + long CourseUnitId, + long CourseId +); \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Models/DTO/UploadFileTaskDto.cs b/HwProj.ContentService/HwProj.ContentService.API/Models/DTO/UploadFileTaskDto.cs new file mode 100644 index 000000000..2bd874118 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Models/DTO/UploadFileTaskDto.cs @@ -0,0 +1,9 @@ +namespace HwProj.ContentService.API.Models.DTO; + +public record UploadFileTaskDto( + long FileRecordId, + string LocalFilePath, + string ContentType, + string ExternalKey, + string UploaderId +); \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Models/DTO/UploadFileToS3Dto.cs b/HwProj.ContentService/HwProj.ContentService.API/Models/DTO/UploadFileToS3Dto.cs new file mode 100644 index 000000000..08f32faec --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Models/DTO/UploadFileToS3Dto.cs @@ -0,0 +1,8 @@ +namespace HwProj.ContentService.API.Models.DTO; + +public record UploadFileToS3Dto( + Stream FileStream, + string ContentType, + string ExternalKey, + string UploaderId +); \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Models/Database/ContentContext.cs b/HwProj.ContentService/HwProj.ContentService.API/Models/Database/ContentContext.cs new file mode 100644 index 000000000..c103740a2 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Models/Database/ContentContext.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore; + +namespace HwProj.ContentService.API.Models.Database; + +public class ContentContext(DbContextOptions options) : DbContext(options) +{ + public DbSet FileRecords { get; set; } + public DbSet FileToCourseUnits { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasIndex(fr => new { fr.Status }); + + modelBuilder.Entity() + .HasKey(ftc => new { ftc.FileRecordId, ftc.CourseUnitType, ftc.CourseUnitId }); + modelBuilder.Entity() + .HasIndex(ftc => new { ftc.FileRecordId }); + modelBuilder.Entity() + .HasIndex(ftc => new { ftc.CourseId }); + } +} diff --git a/HwProj.ContentService/HwProj.ContentService.API/Models/Database/FileRecord.cs b/HwProj.ContentService/HwProj.ContentService.API/Models/Database/FileRecord.cs new file mode 100644 index 000000000..6d3ac46d8 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Models/Database/FileRecord.cs @@ -0,0 +1,16 @@ +using HwProj.ContentService.API.Models.Enums; +using HwProj.Repositories; + +namespace HwProj.ContentService.API.Models.Database; + +public record FileRecord +{ + public long Id { get; set; } + public required FileStatus Status { get; set; } + public required string OriginalName { get; init; } + public string? LocalPath { get; set; } + public string? ExternalKey { get; set; } + public required long SizeInBytes { get; init; } + public required string ContentType { get; init; } + public required int ReferenceCount { get; set; } +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Models/Database/FileToCourseUnit.cs b/HwProj.ContentService/HwProj.ContentService.API/Models/Database/FileToCourseUnit.cs new file mode 100644 index 000000000..aa6630547 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Models/Database/FileToCourseUnit.cs @@ -0,0 +1,13 @@ +using HwProj.ContentService.API.Models.Enums; + +namespace HwProj.ContentService.API.Models.Database; + +public record FileToCourseUnit +{ + public required long FileRecordId { get; init; } + public FileRecord FileRecord { get; set; } + + public required long CourseUnitId { get; init; } + public required CourseUnitType CourseUnitType { get; init; } + public required long CourseId { get; init; } +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Models/Enums/CourseUnitType.cs b/HwProj.ContentService/HwProj.ContentService.API/Models/Enums/CourseUnitType.cs new file mode 100644 index 000000000..b1c836f1b --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Models/Enums/CourseUnitType.cs @@ -0,0 +1,8 @@ +namespace HwProj.ContentService.API.Models.Enums; + +public enum CourseUnitType +{ + Homework, + Task, + Solution +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Models/Enums/FileStatus.cs b/HwProj.ContentService/HwProj.ContentService.API/Models/Enums/FileStatus.cs new file mode 100644 index 000000000..d1d61df68 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Models/Enums/FileStatus.cs @@ -0,0 +1,10 @@ +namespace HwProj.ContentService.API.Models.Enums; + +public enum FileStatus +{ + Uploading = 0, + UploadingError = 1, + ReadyToUse = 2, + Deleting = 3, + DeletingError = 4 +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/DeleteFileMessage.cs b/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/DeleteFileMessage.cs new file mode 100644 index 000000000..34401636e --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/DeleteFileMessage.cs @@ -0,0 +1,6 @@ +namespace HwProj.ContentService.API.Models.Messages; + +public record DeleteFileMessage( + long FileId, + Scope FileScope, + string SenderId) : IProcessFileMessage; \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/FileDeletedMessage.cs b/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/FileDeletedMessage.cs new file mode 100644 index 000000000..8dbb12cb7 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/FileDeletedMessage.cs @@ -0,0 +1,5 @@ +namespace HwProj.ContentService.API.Models.Messages; + +public record FileDeletedMessage( + long FileId, + string SenderId) : IProcessFileMessage; \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/IProcessFileMessage.cs b/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/IProcessFileMessage.cs new file mode 100644 index 000000000..f82cad615 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/IProcessFileMessage.cs @@ -0,0 +1,6 @@ +namespace HwProj.ContentService.API.Models.Messages; + +public interface IProcessFileMessage +{ + public string SenderId { get; init; } +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/ReDeleteFileMessage.cs b/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/ReDeleteFileMessage.cs new file mode 100644 index 000000000..19bc22977 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/ReDeleteFileMessage.cs @@ -0,0 +1,5 @@ +namespace HwProj.ContentService.API.Models.Messages; + +public record ReDeleteFileMessage( + long FileId, + string SenderId) : IProcessFileMessage; \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/ReUploadFileMessage.cs b/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/ReUploadFileMessage.cs new file mode 100644 index 000000000..17ebcbaf7 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/ReUploadFileMessage.cs @@ -0,0 +1,5 @@ +namespace HwProj.ContentService.API.Models.Messages; + +public record ReUploadFileMessage( + long FileId, + string SenderId) : IProcessFileMessage; \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/UpdateStatusMessage.cs b/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/UpdateStatusMessage.cs new file mode 100644 index 000000000..13f177645 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/UpdateStatusMessage.cs @@ -0,0 +1,9 @@ +using HwProj.ContentService.API.Models.Enums; + +namespace HwProj.ContentService.API.Models.Messages; + +public record UpdateStatusMessage( + long FileId, + FileStatus NewStatus, + string? LocalFilePath, + string SenderId) : IProcessFileMessage; \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/UploadFileMessage.cs b/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/UploadFileMessage.cs new file mode 100644 index 000000000..f52b8497b --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Models/Messages/UploadFileMessage.cs @@ -0,0 +1,9 @@ +namespace HwProj.ContentService.API.Models.Messages; + +public record UploadFileMessage( + Scope Scope, + string LocalFilePath, + string ContentType, + string OriginalName, + long SizeInBytes, + string SenderId) : IProcessFileMessage; \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Models/Scope.cs b/HwProj.ContentService/HwProj.ContentService.API/Models/Scope.cs new file mode 100644 index 000000000..6849165a1 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Models/Scope.cs @@ -0,0 +1,9 @@ +using HwProj.ContentService.API.Models.Enums; + +namespace HwProj.ContentService.API.Models; + +public record Scope( + long CourseId, + CourseUnitType CourseUnitType, + long CourseUnitId +); \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Program.cs b/HwProj.ContentService/HwProj.ContentService.API/Program.cs index 04aa44adb..e26c0201e 100644 --- a/HwProj.ContentService/HwProj.ContentService.API/Program.cs +++ b/HwProj.ContentService/HwProj.ContentService.API/Program.cs @@ -1,18 +1,31 @@ using HwProj.ContentService.API.Extensions; +using HwProj.ContentService.API.Services.Interfaces; var builder = WebApplication.CreateBuilder(args); -builder.Services.ConfigureWithAWS(builder.Configuration); +builder.Services.ConfigureWithAWS(builder.Environment, builder.Configuration); // Увеличиваем размер принимаемых запросов до 200 МБ -builder.WebHost.ConfigureKestrel(options => -{ - options.Limits.MaxRequestBodySize = 200 * 1024 * 1024; -}); +builder.WebHost.ConfigureKestrel(options => { options.Limits.MaxRequestBodySize = 200 * 1024 * 1024; }); +// Увеличиваем допустимое время ожидания ASP.NET при остановке сервиса +builder.WebHost.UseShutdownTimeout(TimeSpan.FromMinutes(10)); + var app = builder.Build(); +// Не вызываем ConfigureHwProj из-за проблем с app.UseMvc и настройками маппинга контроллеров (.NET 8 / .NET Core 2.2) +app.ConfigureWebApp(); + // При необходимости создаем пустой бакет в хранилище -await app.CreateBucketIfNotExists(); +if (!app.Environment.IsDevelopment()) await app.CreateBucketIfNotExists(); + +var lifetime = app.Services.GetRequiredService(); +lifetime.ApplicationStarted.Register(async () => +{ + using var scope = app.Services.CreateScope(); + var recoveryService = scope.ServiceProvider.GetRequiredService(); + + // В результате последней остановки сервиса некоторые файлы могли остаться в "промежуточном" состоянии Uploading или Deleting. + // После старта приложения отправим для этих файлов сообщения в канал, чтобы их попробовали загрузить/удалить и обновили статус. + await recoveryService.ReProcessPendingFiles(); +}); -// Не вызываем ConfigureHwProj из-за проблем с app.UseMvc и настройками маппинга контроллеров (.NET 8 / .NET Core 2.2) -app.ConfigureWebApplicationParameters(); app.Run(); \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Repositories/FileRecordRepository.cs b/HwProj.ContentService/HwProj.ContentService.API/Repositories/FileRecordRepository.cs new file mode 100644 index 000000000..2fe0c92d4 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Repositories/FileRecordRepository.cs @@ -0,0 +1,177 @@ +using System.Linq.Expressions; +using HwProj.ContentService.API.Models; +using HwProj.ContentService.API.Models.Database; +using HwProj.ContentService.API.Models.Enums; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; +using HwProj.ContentService.API.Extensions; + +namespace HwProj.ContentService.API.Repositories; + +public class FileRecordRepository : IFileRecordRepository +{ + private readonly ContentContext _contentContext; + + public FileRecordRepository(ContentContext contentContext) + { + _contentContext = contentContext; + } + + public async Task AddWithCourseUnitInfoAsync(FileRecord fileRecord, Scope scope) + { + await using var transaction = await _contentContext.Database.BeginTransactionAsync(); + + await _contentContext.FileRecords.AddAsync(fileRecord); + await _contentContext.SaveChangesAsync(); + + var fileRecordId = fileRecord.Id; + var fileToCourseUnit = new FileToCourseUnit + { + FileRecordId = fileRecordId, + CourseUnitId = scope.CourseUnitId, + CourseUnitType = scope.CourseUnitType, + CourseId = scope.CourseId + }; + await _contentContext.FileToCourseUnits.AddAsync(fileToCourseUnit); + await _contentContext.SaveChangesAsync(); + + await transaction.CommitAsync(); + return fileRecordId; + } + + public async Task UpdateStatusAsync(List fileRecordIds, FileStatus newStatus) + => await _contentContext.FileRecords + .AsNoTracking() + .Where(fr => fileRecordIds.Contains(fr.Id)) + .ExecuteUpdateAsync(setters => + setters.SetProperty(fr => fr.Status, newStatus) + ); + + public async Task GetFileRecordByIdAsync(long fileRecordId) + => await _contentContext.FileRecords + .AsNoTracking() + .SingleOrDefaultAsync(fr => fr.Id == fileRecordId); + + public async Task?> GetScopesAsync(long fileRecordId) + => await _contentContext.FileToCourseUnits + .AsNoTracking() + .Where(fr => fr.FileRecordId == fileRecordId) + .Select(fc => fc.ToScope()) + .ToListAsync(); + + public async Task> GetByScopeAsync(Scope scope) + => await _contentContext.FileToCourseUnits + .AsNoTracking() + .Where(fc => fc.CourseUnitType == scope.CourseUnitType + && fc.CourseUnitId == scope.CourseUnitId) + .Select(fc => fc.FileRecord) + .ToListAsync(); + + public async Task> GetAsync(long courseId, FileStatus? filesStatus = null, + CourseUnitType? courseUnitType = null) + { + IQueryable query = _contentContext.FileToCourseUnits + .AsNoTracking() + .Where(fc => fc.CourseId == courseId) + .Include(fc => fc.FileRecord); + + if (filesStatus != null) + query = query.Where(fc => fc.FileRecord.Status == filesStatus); + + if (courseUnitType != null) + query = query.Where(fc => fc.CourseUnitType == courseUnitType); + + return await query.ToListAsync(); + } + + public async Task> GetIdsByStatusAsync(FileStatus status) + => await _contentContext.FileRecords + .AsNoTracking() + .Where(fr => fr.Status == status) + .Select(fr => fr.Id) + .ToListAsync(); + + public async Task DeleteWithCourseUnitInfoAsync(long fileRecordId) + { + await using var transaction = await _contentContext.Database.BeginTransactionAsync(); + await _contentContext.FileToCourseUnits + .AsNoTracking() + .Where(ftc => ftc.FileRecordId == fileRecordId) + .ExecuteDeleteAsync(); + await _contentContext.FileRecords + .AsNoTracking() + .Where(f => f.Id == fileRecordId) + .ExecuteDeleteAsync(); + await transaction.CommitAsync(); + } + + public async Task DeleteWithCourseUnitInfoAsync(List fileRecordIds) + { + await using var transaction = await _contentContext.Database.BeginTransactionAsync(); + await _contentContext.FileToCourseUnits + .AsNoTracking() + .Where(ftc => fileRecordIds.Contains(ftc.FileRecordId)) + .ExecuteDeleteAsync(); + await _contentContext.FileRecords + .AsNoTracking() + .Where(f => fileRecordIds.Contains(f.Id)) + .ExecuteDeleteAsync(); + await transaction.CommitAsync(); + } + + /// + /// Уменьшает количество ссылок на файл на 1 и удаляет соответствующую запись из таблицы FileToCourseUnit. + /// Если количество ссылок 0, ничего не происходит. + /// + /// количество ссылок на файл после выполнения метода. + public async Task ReduceReferenceCountAsync(FileRecord fileRecord, Scope scope) + { + await using var transaction = await _contentContext.Database.BeginTransactionAsync(); + + await _contentContext.FileToCourseUnits + .AsNoTracking() + .Where(fc => fc.FileRecordId == fileRecord.Id + && fc.CourseUnitType == scope.CourseUnitType + && fc.CourseUnitId == scope.CourseUnitId) + .ExecuteDeleteAsync(); + + if (fileRecord.ReferenceCount > 0) + { + fileRecord.ReferenceCount--; + await _contentContext.FileRecords + .AsNoTracking() + .Where(fr => fr.Id == fileRecord.Id) + .ExecuteUpdateAsync(setters => + setters.SetProperty(fr => fr!.ReferenceCount, fileRecord.ReferenceCount) + ); + } + + await transaction.CommitAsync(); + return fileRecord.ReferenceCount; + } + + /// Переносит файлы с помощью добавления записей в FileToCourseUnit согласно переданному отображению. + /// Увеличивает число ссылок на файлы на число добавленных записей, соответствующих файлу. + public async Task AddFileUnitsAsync(List unitsToAdd) + { + await using var transaction = await _contentContext.Database.BeginTransactionAsync(); + + await _contentContext.FileToCourseUnits.AddRangeAsync(unitsToAdd); + foreach (var unit in unitsToAdd) + { + await UpdateAsync( + unit.FileRecordId, + setters => setters.SetProperty(x => x.ReferenceCount, x => x.ReferenceCount + 1)); + } + + await _contentContext.SaveChangesAsync(); + await transaction.CommitAsync(); + } + + public async Task UpdateAsync(long id, + Expression, SetPropertyCalls>> setPropertyCalls) + => await _contentContext.FileRecords + .AsNoTracking() + .Where(fr => fr.Id == id) + .ExecuteUpdateAsync(setPropertyCalls); +} diff --git a/HwProj.ContentService/HwProj.ContentService.API/Repositories/IFileRecordRepository.cs b/HwProj.ContentService/HwProj.ContentService.API/Repositories/IFileRecordRepository.cs new file mode 100644 index 000000000..f27630598 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Repositories/IFileRecordRepository.cs @@ -0,0 +1,24 @@ +using System.Linq.Expressions; +using HwProj.ContentService.API.Models; +using HwProj.ContentService.API.Models.Database; +using HwProj.ContentService.API.Models.Enums; +using Microsoft.EntityFrameworkCore.Query; + +namespace HwProj.ContentService.API.Repositories; + +public interface IFileRecordRepository +{ + public Task AddWithCourseUnitInfoAsync(FileRecord fileRecord, Scope scope); + public Task UpdateStatusAsync(List fileRecordIds, FileStatus newStatus); + public Task UpdateAsync(long id, + Expression, SetPropertyCalls>> setPropertyCalls); + public Task GetFileRecordByIdAsync(long fileRecordId); + public Task?> GetScopesAsync(long fileRecordId); + public Task> GetByScopeAsync(Scope scope); + public Task> GetAsync(long courseId, FileStatus? filesStatus = null, CourseUnitType? courseUnitType = null); + public Task> GetIdsByStatusAsync(FileStatus status); + public Task DeleteWithCourseUnitInfoAsync(long fileRecordId); + public Task DeleteWithCourseUnitInfoAsync(List fileRecordIds); + public Task AddFileUnitsAsync(List unitsToAdd); + public Task ReduceReferenceCountAsync(FileRecord fileRecord, Scope scope); +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Services/FileKeyService.cs b/HwProj.ContentService/HwProj.ContentService.API/Services/FileKeyService.cs index d84861008..75540ec7f 100644 --- a/HwProj.ContentService/HwProj.ContentService.API/Services/FileKeyService.cs +++ b/HwProj.ContentService/HwProj.ContentService.API/Services/FileKeyService.cs @@ -1,40 +1,54 @@ +using System.Security.Cryptography; +using System.Text; using System.Text.RegularExpressions; -using HwProj.Models.ContentService.DTO; +using Cyrillic.Convert; +using HwProj.ContentService.API.Models; +using HwProj.ContentService.API.Services.Interfaces; namespace HwProj.ContentService.API.Services; public class FileKeyService : IFileKeyService { - public string BuildFileKey(UploadFileDTO dto) - => $"courses/{dto.CourseId}/lecturers/homeworks/{dto.HomeworkId}/files/{dto.File.FileName}"; - - public bool GetHomeworkIdFromKey(string fileKey, out long homeworkId) + // Максимальная длина имени файла в Ubuntu (в байтах) + private const int MaxFileNameOnServerBytes = 255; + + public string BuildS3FileKey(Scope scope, string fileName, long fileRecordId) { - var match = Regex.Match( - fileKey, - @"/homeworks/(?\d+)(?=/|$)", - RegexOptions.IgnoreCase - ); + var pureName = SanitizeFileName(fileName); + return $"courses/{scope.CourseId}/{scope.CourseUnitType}s/{scope.CourseUnitId}/{fileRecordId}_{pureName}"; + } - return long.TryParse(match.Groups["homeworkId"].Value, out homeworkId); + public string BuildServerFilePath(Scope scope, string fileName) + { + var pureName = SanitizeFileName(fileName); + if (Encoding.UTF8.GetByteCount(pureName) > MaxFileNameOnServerBytes) + pureName = HashFileName(fileName); + return $"courses/{scope.CourseId}/{scope.CourseUnitType}s/{scope.CourseUnitId}/{pureName}"; } - public bool GetCourseIdFromKey(string fileKey, out long courseId) + private static string SanitizeFileName(string fileName) { - var match = Regex.Match( - fileKey, - @"courses/(?\d+)(?=/|$)", - RegexOptions.IgnoreCase - ); + // Выполняем транслитерацию + var transliteratedName = fileName.ToRussianLatin(); - return long.TryParse(match.Groups["courseId"].Value, out courseId); + // Заменяем пробелы на символы подчеркивания + transliteratedName = transliteratedName.Replace(' ', '_'); + + // Заменяем другие нежелательные символы + // В данном случае заменяем все, кроме букв, цифр, дефисов и подчеркиваний + transliteratedName = Regex.Replace(transliteratedName, @"[^\w\-\.]", ""); + + return transliteratedName; } - public string GetFileName(string fileKey) - => fileKey.Split('/').Last(); + private static string HashFileName(string longFileName) + { + using var sha256 = SHA256.Create(); + + var hashedBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(longFileName)); + var hash = BitConverter.ToString(hashedBytes).Replace('/', '_').Substring(0, 30); - public string GetFilesSearchPrefix(long courseId, long homeworkId = -1) - => homeworkId == -1 - ? $"courses/{courseId}/lecturers/" - : $"courses/{courseId}/lecturers/homeworks/{homeworkId}/files/"; + var extension = Path.GetExtension(longFileName); + return $"{hash}{extension}"; + } } \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Services/FilesInfoService.cs b/HwProj.ContentService/HwProj.ContentService.API/Services/FilesInfoService.cs new file mode 100644 index 000000000..9f7a78cce --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Services/FilesInfoService.cs @@ -0,0 +1,87 @@ +using HwProj.ContentService.API.Extensions; +using HwProj.ContentService.API.Models; +using HwProj.ContentService.API.Models.Database; +using HwProj.ContentService.API.Models.Enums; +using HwProj.ContentService.API.Repositories; +using HwProj.ContentService.API.Services.Interfaces; +using HwProj.Models.ContentService.DTO; + +namespace HwProj.ContentService.API.Services; + +public class FilesInfoService : IFilesInfoService +{ + private readonly IFileRecordRepository _fileRecordRepository; + + public FilesInfoService(IFileRecordRepository fileRecordRepository) + { + _fileRecordRepository = fileRecordRepository; + } + + public async Task> GetFilesStatusesAsync(Scope filesScope) + { + var filesRecords = await _fileRecordRepository.GetByScopeAsync(filesScope); + return filesRecords.Select(fr => new FileInfoDTO + { + Id = fr.Id, + Name = fr.OriginalName, + SizeInBytes = fr.SizeInBytes, + Status = fr.Status.ToString(), + CourseUnitType = filesScope.CourseUnitType.ToString(), + CourseUnitId = filesScope.CourseUnitId + }).ToList(); + } + + public async Task GetFileExternalKeyAsync(long fileId) + { + var fileRecord = await _fileRecordRepository.GetFileRecordByIdAsync(fileId); + return fileRecord?.ExternalKey; + } + + public async Task?> GetFileScopesAsync(long fileId) + { + var fileToCourseUnit = await _fileRecordRepository.GetScopesAsync(fileId); + return fileToCourseUnit; + } + + public async Task> GetFilesInfoAsync(long courseId, FileStatus? filesStatus, + CourseUnitType courseUnitType) + { + var filesRecords = await _fileRecordRepository.GetAsync(courseId, filesStatus, courseUnitType); + return filesRecords.Select(fcu => new FileInfoDTO + { + Id = fcu.FileRecord.Id, + Name = fcu.FileRecord.OriginalName, + SizeInBytes = fcu.FileRecord.SizeInBytes, + Status = fcu.FileRecord.Status.ToString(), + CourseUnitType = fcu.CourseUnitType.ToString(), + CourseUnitId = fcu.CourseUnitId + }).ToList(); + } + + public async Task TransferFilesFromCourse(CourseFilesTransferDto filesTransfer) + { + var map = filesTransfer.HomeworksMapping.ToDictionary( + x => new Scope(filesTransfer.SourceCourseId, CourseUnitType.Homework, x.Source), + x => new Scope(filesTransfer.TargetCourseId, CourseUnitType.Homework, x.Target) + ); + + var sourceCourseUnits = await _fileRecordRepository.GetAsync(filesTransfer.SourceCourseId); + var unitsToAdd = sourceCourseUnits + .Select(unit => (unit.FileRecord, Scope: unit.ToScope())) + .Where(pair => map.ContainsKey(pair.Scope)) + .Select(pair => + { + var targetScope = map[pair.Scope]; + return new FileToCourseUnit + { + FileRecordId = pair.FileRecord.Id, + CourseId = targetScope.CourseId, + CourseUnitId = targetScope.CourseUnitId, + CourseUnitType = targetScope.CourseUnitType + }; + }) + .ToList(); + + await _fileRecordRepository.AddFileUnitsAsync(unitsToAdd); + } +} diff --git a/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IFileKeyService.cs b/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IFileKeyService.cs new file mode 100644 index 000000000..b62edf502 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IFileKeyService.cs @@ -0,0 +1,9 @@ +using HwProj.ContentService.API.Models; + +namespace HwProj.ContentService.API.Services.Interfaces; + +public interface IFileKeyService +{ + public string BuildS3FileKey(Scope scope, string fileName, long fileRecordId); + public string BuildServerFilePath(Scope scope, string fileName); +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IFilesInfoService.cs b/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IFilesInfoService.cs new file mode 100644 index 000000000..8c97b3289 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IFilesInfoService.cs @@ -0,0 +1,15 @@ +using HwProj.ContentService.API.Models; +using HwProj.ContentService.API.Models.Database; +using HwProj.ContentService.API.Models.Enums; +using HwProj.Models.ContentService.DTO; + +namespace HwProj.ContentService.API.Services.Interfaces; + +public interface IFilesInfoService +{ + public Task> GetFilesStatusesAsync(Scope filesScope); + public Task GetFileExternalKeyAsync(long fileId); + public Task?> GetFileScopesAsync(long fileId); + public Task> GetFilesInfoAsync(long courseId, FileStatus? filesStatus, CourseUnitType courseUnitType); + public Task TransferFilesFromCourse(CourseFilesTransferDto filesTransfer); +} diff --git a/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/ILocalFilesService.cs b/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/ILocalFilesService.cs new file mode 100644 index 000000000..14f544b1d --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/ILocalFilesService.cs @@ -0,0 +1,11 @@ +using HwProj.ContentService.API.Models; +using HwProj.Models.Result; + +namespace HwProj.ContentService.API.Services.Interfaces; + +public interface ILocalFilesService +{ + public Task SaveFile(Stream file, string filePath); + public Result DeleteFile(string pathToFile); + public Stream GetFileStream(string pathToFile); +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IMessageProducer.cs b/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IMessageProducer.cs new file mode 100644 index 000000000..f543165b3 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IMessageProducer.cs @@ -0,0 +1,14 @@ +using HwProj.ContentService.API.Models; +using HwProj.ContentService.API.Models.Messages; + +namespace HwProj.ContentService.API.Services.Interfaces; + +public interface IMessageProducer +{ + public Task PushUploadFilesMessages(List messages); + public Task PushReUploadFilesMessages(List fileIds, string userId); + public Task PushUpdateFileStatusMessage(UpdateStatusMessage updateStatusMessage); + public Task PushFileDeletedMessage(FileDeletedMessage fileDeletedMessage); + public Task PushDeleteFilesMessages(Scope scope, List fileIds, string userId); + public Task PushReDeleteFilesMessages(List fileIds, string userId); +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IRecoveryService.cs b/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IRecoveryService.cs new file mode 100644 index 000000000..bebf7ca8b --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IRecoveryService.cs @@ -0,0 +1,6 @@ +namespace HwProj.ContentService.API.Services.Interfaces; + +public interface IRecoveryService +{ + public Task ReProcessPendingFiles(); +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IS3FilesService.cs b/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IS3FilesService.cs new file mode 100644 index 000000000..82e8ef65d --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IS3FilesService.cs @@ -0,0 +1,13 @@ +using HwProj.ContentService.API.Models.DTO; +using HwProj.Models.Result; + +namespace HwProj.ContentService.API.Services.Interfaces; + +public interface IS3FilesService +{ + public Task UploadFileAsync(UploadFileToS3Dto uploadFileToS3Dto); + public Task> GetBucketFilesAsync(string bucketName, string filePathPattern); + public Task> GetDownloadUrl(string fileKey); + public Task CheckFileExistence(string fileKey); + public Task DeleteFileAsync(string fileKey); +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Services/LocalFilesService.cs b/HwProj.ContentService/HwProj.ContentService.API/Services/LocalFilesService.cs new file mode 100644 index 000000000..9d6cf1952 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Services/LocalFilesService.cs @@ -0,0 +1,62 @@ +using HwProj.ContentService.API.Configuration; +using HwProj.ContentService.API.Services.Interfaces; +using HwProj.Models.Result; +using Microsoft.Extensions.Options; + +namespace HwProj.ContentService.API.Services; + +public class LocalFilesService : ILocalFilesService +{ + private readonly string _storagePath; + + public LocalFilesService(IOptions localStorageConfiguration) + { + _storagePath = localStorageConfiguration.Value.Path ?? + throw new NullReferenceException("Не указан путь к локальному хранилищу файлов (для временного хранения)"); + Directory.CreateDirectory(_storagePath); + } + + public async Task SaveFile(Stream fileStream, string filePath) + { + var fullPath = Path.Combine(_storagePath, filePath); + + var directoryPath = Path.GetDirectoryName(fullPath); + if (directoryPath is not null && !Directory.Exists(directoryPath)) + Directory.CreateDirectory(directoryPath); + + await using var stream = new FileStream(fullPath, FileMode.Create); + await fileStream.CopyToAsync(stream); + } + + public Result DeleteFile(string pathToFile) + { + var fullPath = Path.Combine(_storagePath, pathToFile); + if (!File.Exists(fullPath)) + { + return Result.Failed("Файл по пути {filePath} не найден", pathToFile); + } + + File.Delete(fullPath); + + // Если папка файла теперь пуста, удаляем её + var directoryPath = Path.GetDirectoryName(fullPath); + if (directoryPath is not null && IsDirectoryEmpty(directoryPath)) + Directory.Delete(directoryPath); + + return Result.Success(); + } + + public Stream GetFileStream(string pathToFile) + { + var fullPath = Path.Combine(_storagePath, pathToFile); + if (!File.Exists(fullPath)) + { + throw new FileNotFoundException($"Файл по пути {pathToFile} не найден."); + } + + return new FileStream(fullPath, FileMode.Open, FileAccess.Read); + } + + private bool IsDirectoryEmpty(string path) + => Directory.GetFiles(path).Length == 0 && Directory.GetDirectories(path).Length == 0; +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Services/MessageConsumer.cs b/HwProj.ContentService/HwProj.ContentService.API/Services/MessageConsumer.cs new file mode 100644 index 000000000..f5b2584cc --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Services/MessageConsumer.cs @@ -0,0 +1,339 @@ +using System.Threading.Channels; +using HwProj.ContentService.API.Models.Database; +using HwProj.ContentService.API.Models.DTO; +using HwProj.ContentService.API.Models.Enums; +using HwProj.ContentService.API.Models.Messages; +using HwProj.ContentService.API.Repositories; +using HwProj.ContentService.API.Services.Interfaces; + +namespace HwProj.ContentService.API.Services; + +public class MessageConsumer : BackgroundService +{ + private readonly ChannelReader _channelReader; + private readonly ILogger _logger; + private readonly HashSet _filesInProcessing = new(); + + private readonly IServiceScopeFactory _serviceScopeFactory; + private readonly IMessageProducer _messageProducer; + private readonly ILocalFilesService _localFilesService; + private readonly IS3FilesService _s3FilesService; + private readonly IFileKeyService _fileKeyService; + + public MessageConsumer(ChannelReader channelReader, ILogger logger, + IMessageProducer messageProducer, IS3FilesService s3FilesService, IFileKeyService fileKeyService, + IServiceScopeFactory serviceScopeFactory, ILocalFilesService localFilesService) + { + _channelReader = channelReader; + _logger = logger; + _messageProducer = messageProducer; + _s3FilesService = s3FilesService; + _fileKeyService = fileKeyService; + _serviceScopeFactory = serviceScopeFactory; + _localFilesService = localFilesService; + } + + protected override async Task ExecuteAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("Обработчик сообщений MessageConsumer запущен"); + + // Можем так сделать, поскольку MessageConsumer работает с базой строго последовательно (последовательно обрабатывает сообщения) + using var scope = _serviceScopeFactory.CreateScope(); + var fileRecordRepository = scope.ServiceProvider.GetRequiredService(); + + await foreach (var message in _channelReader.ReadAllAsync(cancellationToken)) + { + await ProcessMessage(message, fileRecordRepository); + } + } + + private async Task ProcessMessage(IProcessFileMessage message, IFileRecordRepository fileRecordRepository) + { + var processingTask = message switch + { + UploadFileMessage uploadFileMessage => HandleUploadFileMessage(uploadFileMessage, fileRecordRepository), + ReUploadFileMessage reUploadFileMessage => HandleReUploadFileMessage(reUploadFileMessage, fileRecordRepository), + UpdateStatusMessage updateStatusMessage => HandleUpdateStatusMessage(updateStatusMessage, fileRecordRepository), + DeleteFileMessage deleteFileMessage => HandleDeleteFileMessage(deleteFileMessage, fileRecordRepository), + ReDeleteFileMessage reDeleteFileMessage => HandleReDeleteFileMessage(reDeleteFileMessage, fileRecordRepository), + FileDeletedMessage fileDeletedMessage => HandleFileDeletedMessage(fileDeletedMessage, fileRecordRepository), + _ => HandleUnknownMessage(message) + }; + + await processingTask; + } + + public override async Task StopAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("Приступаем к завершению работы обработчика сообщений MessageConsumer"); + using var scope = _serviceScopeFactory.CreateScope(); + var fileRecordRepository = scope.ServiceProvider.GetRequiredService(); + + // Обрабатываем оставшиеся сообщений в канале + while (_channelReader.TryRead(out var message)) + { + await ProcessMessage(message, fileRecordRepository); + } + + // Ждем завершения всех дополнительных задач + while (_filesInProcessing.Count > 0) + { + } + + // Ещё раз обрабатываем оставшиеся сообщения в канале, поскольку некоторые задачи содержат отправку сообщения + while (_channelReader.TryRead(out var message)) + { + await ProcessMessage(message, fileRecordRepository); + } + + _logger.LogInformation("Канал сообщений пуст, обработчик MessageConsumer успешно приостановлен"); + } + + private Task HandleUnknownMessage(IProcessFileMessage message) + { + _logger.LogWarning("Необработанное сообщение типа {messageType} от пользователя {senderId}", + message.GetType().Name, message.SenderId); + return Task.CompletedTask; + } + + private async Task HandleUploadFileMessage(UploadFileMessage message, IFileRecordRepository fileRecordRepository) + { + // Создаем запись о файле в БД + var fileRecord = new FileRecord + { + Status = FileStatus.Uploading, + ReferenceCount = 1, + OriginalName = message.OriginalName, + SizeInBytes = message.SizeInBytes, + ContentType = message.ContentType, + LocalPath = message.LocalFilePath + }; + var fileRecordId = await fileRecordRepository.AddWithCourseUnitInfoAsync(fileRecord, message.Scope); + + // Формируем и устанавливаем ключ для S3, содержащий id записи файла + var s3Key = _fileKeyService.BuildS3FileKey(message.Scope, message.OriginalName, fileRecordId); + await fileRecordRepository.UpdateAsync(fileRecordId, + setters => setters.SetProperty(fr => fr.ExternalKey, s3Key)); + + _logger.LogInformation("Информация о файле {fileId} от пользователя {senderId} успешно добавлена в базу данных", + fileRecordId, message.SenderId); + + // Формируем модель и отправляем задачу на загрузку файла, не блокируя Consumer + var uploadFileTaskDto = new UploadFileTaskDto( + FileRecordId: fileRecordId, + LocalFilePath: message.LocalFilePath, + ContentType: message.ContentType, + ExternalKey: s3Key, + UploaderId: message.SenderId + ); + + // А также сигнализируем, что для fileRecordId есть задача, завершения которой нужно дождаться при остановке сервиса + _filesInProcessing.Add(fileRecordId); + + UploadFileTask(uploadFileTaskDto); + } + + private async Task HandleReUploadFileMessage(ReUploadFileMessage message, IFileRecordRepository fileRecordRepository) + { + var fileRecord = await fileRecordRepository.GetFileRecordByIdAsync(message.FileId); + if (fileRecord is null) + { + _logger.LogError( + "При обработке сообщения на повторную загрузку файла (запрос пользователя {senderId}) в БД не найдена запись FileRecord для файла с id {fileId}", + message.SenderId, message.FileId); + return; + } + + // Сигнализируем, что для fileRecord.Id есть задача, завершения которой нужно дождаться при остановке сервиса + _filesInProcessing.Add(fileRecord.Id); + + // Не блокируя Consumer, начинаем взаимодействие с удаленным S3 по вопросу этого файла + Task.Run(async () => + { + // Если файл уже есть в s3, осталось просто обновить статус + var isInS3 = await _s3FilesService.CheckFileExistence(fileRecord.ExternalKey!); + if (isInS3) + { + var updateStatusMessage = new UpdateStatusMessage( + FileId: fileRecord.Id, + NewStatus: FileStatus.ReadyToUse, + LocalFilePath: null, + SenderId: message.SenderId + ); + await _messageProducer.PushUpdateFileStatusMessage(updateStatusMessage); + return; + } + + // Иначе формируем модель и отправляем стандартную задачу на загрузку + var uploadFileTaskDto = new UploadFileTaskDto( + FileRecordId: fileRecord.Id, + LocalFilePath: fileRecord.LocalPath, + ContentType: fileRecord.ContentType, + ExternalKey: fileRecord.ExternalKey!, + UploaderId: message.SenderId + ); + await UploadFileTask(uploadFileTaskDto); + }); + } + + private async Task HandleUpdateStatusMessage(UpdateStatusMessage message, + IFileRecordRepository fileRecordRepository) + { + await fileRecordRepository.UpdateAsync(message.FileId, + setters => setters.SetProperty(fr => fr.Status, message.NewStatus)); + _logger.LogInformation( + "Статус файла {fileId} успешно обновлён на {newStatus} по запросу пользователя {senderId}", + message.FileId, message.NewStatus, message.SenderId); + + // Если файл перешёл в статус ReadyToUse, то удаляем его из локального хранилища + if (message.NewStatus is FileStatus.ReadyToUse && !string.IsNullOrEmpty(message.LocalFilePath)) + if (_localFilesService.DeleteFile(message.LocalFilePath).Succeeded) + { + _logger.LogInformation("Файл {fileId} удален из локального хранилища по пути {filePath}", + message.FileId, message.LocalFilePath); + + // Удаляем больше не актуальный путь к локальному файлу + await fileRecordRepository.UpdateAsync(message.FileId, + setters => setters.SetProperty(fr => fr.LocalPath, string.Empty)); + } + } + + private async Task HandleDeleteFileMessage(DeleteFileMessage message, IFileRecordRepository fileRecordRepository) + { + var fileRecord = await fileRecordRepository.GetFileRecordByIdAsync(message.FileId); + if (fileRecord is null) + { + _logger.LogError( + "При обработке сообщения на удаление файла (запрос пользователя {senderId}) в БД не найдена запись FileRecord для файла с id {fileId}", + message.SenderId, message.FileId); + return; + } + + if (fileRecord.Status is FileStatus.Uploading) + { + _logger.LogError("Ошибка удаления файла {fileId} пользователем {senderId}: файл ещё загружается", + fileRecord.Id, message.SenderId); + return; + } + + if (fileRecord.ReferenceCount > 1) + { + var newReferenceCount = + await fileRecordRepository.ReduceReferenceCountAsync(fileRecord, message.FileScope); + _logger.LogInformation("Количество ссылок на файл {fileId} уменьшено с {previousReferenceCount} " + + "до {newReferenceCount} по запросу пользователя {senderId}", + message.FileId, fileRecord.ReferenceCount, newReferenceCount, message.SenderId); + return; + } + + await fileRecordRepository.UpdateAsync(message.FileId, + setters => setters.SetProperty(fr => fr.Status, FileStatus.Deleting)); + _logger.LogInformation( + "Статус файла {fileId} успешно обновлён на {status} по запросу пользователя {senderId}", + message.FileId, fileRecord.Status.ToString(), message.SenderId); + + // Сигнализируем, что для message.FileId есть задача, завершения которой нужно дождаться при остановке сервиса + _filesInProcessing.Add(message.FileId); + + DeleteFileTask(message.FileId, fileRecord.ExternalKey!, message.SenderId); + } + + private async Task HandleReDeleteFileMessage(ReDeleteFileMessage message, IFileRecordRepository fileRecordRepository) + { + var fileRecord = await fileRecordRepository.GetFileRecordByIdAsync(message.FileId); + if (fileRecord is null) + { + _logger.LogError( + "При обработке сообщения на повторное удаление файла (запрос пользователя {senderId}) в БД не найдена запись FileRecord для файла с id {fileId}", + message.SenderId, message.FileId); + return; + } + + // Сигнализируем, что для fileRecord.Id есть задача, завершения которой нужно дождаться при остановке сервиса + _filesInProcessing.Add(fileRecord.Id); + + // Не блокируя Consumer, начинаем взаимодействие с удаленным S3 по вопросу этого файла + Task.Run(async () => + { + // Если файла уже нет в s3, осталось просто отправить сообщение для удаления записи файла из БД + var isInS3 = await _s3FilesService.CheckFileExistence(fileRecord.ExternalKey!); + if (!isInS3) + { + var fileDeletedMessage = new FileDeletedMessage( + FileId: fileRecord.Id, + SenderId: message.SenderId + ); + await _messageProducer.PushFileDeletedMessage(fileDeletedMessage); + return; + } + + // Иначе отправляем стандартную задачу на удаление + await DeleteFileTask(fileRecord.Id, fileRecord.ExternalKey!, message.SenderId); + }); + } + + private async Task HandleFileDeletedMessage(FileDeletedMessage message, IFileRecordRepository fileRecordRepository) + { + await fileRecordRepository.DeleteWithCourseUnitInfoAsync(message.FileId); + _logger.LogInformation( + "Информация о файле {fileId} успешно удалена из базы данных по запросу пользователя {senderId}", + message.FileId, message.SenderId); + } + + private async Task UploadFileTask(UploadFileTaskDto uploadFileTaskDto) + { + // Загружаем в S3 + var fileReadStream = _localFilesService.GetFileStream(uploadFileTaskDto.LocalFilePath); + var uploadFileToS3Dto = new UploadFileToS3Dto( + FileStream: fileReadStream, + ContentType: uploadFileTaskDto.ContentType, + ExternalKey: uploadFileTaskDto.ExternalKey, + UploaderId: uploadFileTaskDto.UploaderId + ); + var s3UploadingResult = await _s3FilesService.UploadFileAsync(uploadFileToS3Dto); + await fileReadStream.DisposeAsync(); + + if (!s3UploadingResult.Succeeded) + _logger.LogError("Не удалось загрузить файл {fileId} во внешнее хранилище. Ошибка: {error}", + uploadFileTaskDto.FileRecordId, s3UploadingResult.Errors[0]); + + // Отправляем сообщение на обновление статуса файла в БД в соответствии с результатом загрузки + var updateStatusMessage = new UpdateStatusMessage( + FileId: uploadFileTaskDto.FileRecordId, + NewStatus: s3UploadingResult.Succeeded ? FileStatus.ReadyToUse : FileStatus.UploadingError, + LocalFilePath: uploadFileTaskDto.LocalFilePath, + SenderId: uploadFileToS3Dto.UploaderId + ); + await _messageProducer.PushUpdateFileStatusMessage(updateStatusMessage); + + // Задача для fileId завершена, новое сообщение отправлено в канал + _filesInProcessing.Remove(uploadFileTaskDto.FileRecordId); + } + + private async Task DeleteFileTask(long fileId, string s3Key, string senderId) + { + var s3DeletingResult = await _s3FilesService.DeleteFileAsync(s3Key); + if (s3DeletingResult.Succeeded) + { + var fileDeletedMessage = new FileDeletedMessage(fileId, senderId); + await _messageProducer.PushFileDeletedMessage(fileDeletedMessage); + + // Задача для message.FileId завершена, новое сообщение отправлено в канал + _filesInProcessing.Remove(fileId); + return; + } + + _logger.LogError("Не удалось удалить файл {fileId} из внешнего хранилища по запросу пользователя {senderId}. " + + "Ошибка: {error}", fileId, senderId, s3DeletingResult.Errors[0]); + var updateStatusMessage = new UpdateStatusMessage( + FileId: fileId, + NewStatus: FileStatus.DeletingError, + LocalFilePath: null, + SenderId: senderId + ); + await _messageProducer.PushUpdateFileStatusMessage(updateStatusMessage); + + // Задача для message.FileId завершена, новое сообщение отправлено в канал + _filesInProcessing.Remove(fileId); + } +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Services/MessageProducer.cs b/HwProj.ContentService/HwProj.ContentService.API/Services/MessageProducer.cs new file mode 100644 index 000000000..7a6a12874 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Services/MessageProducer.cs @@ -0,0 +1,92 @@ +using System.Threading.Channels; +using HwProj.ContentService.API.Models; +using HwProj.ContentService.API.Models.Messages; +using HwProj.ContentService.API.Services.Interfaces; + +namespace HwProj.ContentService.API.Services; + +public class MessageProducer : IMessageProducer +{ + private readonly ChannelWriter _channelWriter; + private readonly ILogger _logger; + + public MessageProducer(ChannelWriter channelWriter, ILogger logger) + { + _channelWriter = channelWriter; + _logger = logger; + } + + public async Task PushUploadFilesMessages(List messages) + { + foreach (var uploadFileMessage in messages) + { + await _channelWriter.WriteAsync(uploadFileMessage); + _logger.LogInformation("В канал опубликована задача на загрузку файла {fileName} пользователем {senderId}", + uploadFileMessage.OriginalName, uploadFileMessage.SenderId); + } + } + + public async Task PushReUploadFilesMessages(List fileIds, string userId) + { + foreach (var fileId in fileIds) + { + var reUploadFileMessage = new ReUploadFileMessage( + FileId: fileId, + SenderId: userId + ); + + await _channelWriter.WriteAsync(reUploadFileMessage); + _logger.LogInformation( + "В канал опубликована задача на повторную загрузку файла {fileId} пользователем {senderId}", + fileId, userId); + } + } + + public async Task PushDeleteFilesMessages(Scope filesScope, List fileIds, string userId) + { + var startDeletingFileMessages = fileIds.Select(fileId => + new DeleteFileMessage( + FileId: fileId, + FileScope: filesScope, + SenderId: userId + )); + + foreach (var startDeletingFileMessage in startDeletingFileMessages) + { + await _channelWriter.WriteAsync(startDeletingFileMessage); + _logger.LogInformation("В канал опубликована задача на удаление файла {fileId} пользователем {senderId}", + startDeletingFileMessage.FileId, startDeletingFileMessage.SenderId); + } + } + + public async Task PushReDeleteFilesMessages(List fileIds, string userId) + { + foreach (var fileId in fileIds) + { + var reDeleteFileMessage = new ReDeleteFileMessage( + FileId: fileId, + SenderId: userId + ); + + await _channelWriter.WriteAsync(reDeleteFileMessage); + _logger.LogInformation( + "В канал опубликована задача на повторное удаление файла {fileId} пользователем {senderId}", + fileId, userId); + } + } + + public async Task PushFileDeletedMessage(FileDeletedMessage fileDeletedMessage) + { + await _channelWriter.WriteAsync(fileDeletedMessage); + _logger.LogInformation("В канал опубликована задача на удаление записи файла {fileId} пользователем {senderId}", + fileDeletedMessage.FileId, fileDeletedMessage.SenderId); + } + + public async Task PushUpdateFileStatusMessage(UpdateStatusMessage updateStatusMessage) + { + await _channelWriter.WriteAsync(updateStatusMessage); + _logger.LogInformation( + "В канал опубликована задача на обновление статуса файла {fileId} на {newStatus} пользователем {senderId}", + updateStatusMessage.FileId, updateStatusMessage.NewStatus.ToString(), updateStatusMessage.SenderId); + } +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Services/RecoveryService.cs b/HwProj.ContentService/HwProj.ContentService.API/Services/RecoveryService.cs new file mode 100644 index 000000000..1fe25d375 --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Services/RecoveryService.cs @@ -0,0 +1,62 @@ +using HwProj.ContentService.API.Models; +using HwProj.ContentService.API.Models.Enums; +using HwProj.ContentService.API.Models.Messages; +using HwProj.ContentService.API.Repositories; +using HwProj.ContentService.API.Services.Interfaces; + +namespace HwProj.ContentService.API.Services; + +public class RecoveryService : IRecoveryService +{ + private const string SenderId = "ContentMicroservice"; + + private readonly IFileRecordRepository _fileRecordRepository; + private readonly IMessageProducer _messageProducer; + private readonly ILogger _logger; + + public RecoveryService(IFileRecordRepository fileRecordRepository, ILogger logger, + IMessageProducer messageProducer) + { + _fileRecordRepository = fileRecordRepository; + _logger = logger; + _messageProducer = messageProducer; + } + + public async Task ReProcessPendingFiles() + { + await ReProcessDeletingFilesAsync(); + await ReProcessUploadingFilesAsync(); + } + + private async Task ReProcessUploadingFilesAsync() + { + _logger.LogInformation("Начинаем поиск записей файлов в статусе {Uploading}", FileStatus.Uploading); + var loadingFilesIds = await _fileRecordRepository.GetIdsByStatusAsync(FileStatus.Uploading); + if (loadingFilesIds.Count == 0) + { + _logger.LogInformation("Найдено 0 записей файлов в статусе {Uploading}", FileStatus.Uploading); + return; + } + + _logger.LogInformation( + "Найдено {recordsCount} записей файлов в статусе {Uploading}. Отправляем сообщения для проверки наличия файлов и повторной загрузки", + FileStatus.Uploading, loadingFilesIds.Count); + await _messageProducer.PushReUploadFilesMessages(loadingFilesIds, SenderId); + } + + private async Task ReProcessDeletingFilesAsync() + { + _logger.LogInformation("Начинаем поиск записей файлов в статусе {Deleting}", FileStatus.Deleting); + var deletingFilesIds = await _fileRecordRepository.GetIdsByStatusAsync(FileStatus.Deleting); + if (deletingFilesIds.Count == 0) + { + _logger.LogInformation("Найдено 0 записей файлов в статусе {Deleting}", FileStatus.Deleting); + return; + } + + _logger.LogInformation( + "Найдено {recordsCount} записей в статусе {Deleting}. Приступаем к проверке наличия файлов во внешнем хранилище и обновлению статусов", + FileStatus.Deleting, deletingFilesIds.Count); + await _messageProducer.PushReDeleteFilesMessages(deletingFilesIds, SenderId); + } +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/Services/S3FilesService.cs b/HwProj.ContentService/HwProj.ContentService.API/Services/S3FilesService.cs new file mode 100644 index 000000000..b242fee3c --- /dev/null +++ b/HwProj.ContentService/HwProj.ContentService.API/Services/S3FilesService.cs @@ -0,0 +1,193 @@ +using System.Text.RegularExpressions; +using Amazon.S3; +using Amazon.S3.Model; +using HwProj.ContentService.API.Configuration; +using HwProj.ContentService.API.Extensions; +using HwProj.ContentService.API.Models.DTO; +using HwProj.ContentService.API.Models.Enums; +using HwProj.ContentService.API.Services.Interfaces; +using HwProj.Models.Result; +using Microsoft.Extensions.Options; + +namespace HwProj.ContentService.API.Services; + +public class S3FilesService : IS3FilesService +{ + private const int FileDownloadUrlExpirationMinutes = 10; + private const string UploaderIdMetadataKey = "uploader-id"; + private const string AwsMetaDataPrefix = "x-amz-meta-"; + private readonly string _bucketName; + + private readonly IAmazonS3 _s3AmazonClient; + + public S3FilesService(IAmazonS3 s3Client, IOptions externalStorageConfiguration) + { + _s3AmazonClient = s3Client; + _bucketName = externalStorageConfiguration.Value.DefaultBucketName + ?? throw new NullReferenceException("Не указано имя бакета для сохранения файлов"); + } + + // Метод позволяет получить файлы вместе с дополнительной информацией из бакета. + // filePathPattern должен содержать группы FileName, HomeworkId и CourseId, + // чтобы эту дополнительную информацию из пути к файлу извлечь + public async Task> GetBucketFilesAsync(string bucketName, string filePathPattern) + { + var bucketKeys = await _s3AmazonClient.GetAllObjectKeysAsync(bucketName, string.Empty, null); + var filesBucketKeys = bucketKeys.Where(key => key[^1] != '/'); + + var regex = new Regex(filePathPattern, RegexOptions.Compiled); + + var tasks = filesBucketKeys.Select(async (key) => + { + // Получаем метаданные объекта, чтобы извлечь ContentType + var metadataResponse = await _s3AmazonClient.GetObjectMetadataAsync(new GetObjectMetadataRequest + { + BucketName = bucketName, + Key = key + }); + + // Получаем сам файл + var fileStream = await GetFileStream(bucketName, key); + + var match = regex.Match(key); + + return new FileTransferDTO( + Name: match.Groups["FileName"].Value, + SizeInBytes: metadataResponse.Headers.ContentLength, + ContentType: metadataResponse.Headers.ContentType, + FileStream: fileStream, + CourseUnitType: CourseUnitType.Homework, + CourseUnitId: long.Parse(match.Groups["HomeworkId"].Value), + CourseId: long.Parse(match.Groups["CourseId"].Value) + ); + }).ToList(); + + var fileTransfers = await Task.WhenAll(tasks); + return fileTransfers.ToList(); + } + + // Если файл с таким ключем уже существует, в текущей реализации он будет перезаписываться + public async Task UploadFileAsync(UploadFileToS3Dto uploadFileToS3Dto) + { + try + { + var request = CreateUploadRequest(uploadFileToS3Dto); + var response = await _s3AmazonClient.PutObjectAsync(request); + return response.IsSuccessStatusCode() + ? Result.Success() + : Result.Failed($"Не удалось загрузить файл. Код ответа хранилища: {(int)response.HttpStatusCode}"); + } + catch (Exception e) + { + return Result.Failed(e.Message); + } + } + + public async Task> GetDownloadUrl(string fileKey) + { + try + { + var url = await _s3AmazonClient.GetPreSignedURLAsync( + new GetPreSignedUrlRequest + { + BucketName = _bucketName, + Key = fileKey, + Expires = DateTime.UtcNow.AddMinutes(FileDownloadUrlExpirationMinutes) + }); + + return url != null + ? Result.Success(url) + : Result.Failed("Файл не найден"); + } + catch (Exception e) + { + return Result.Failed(e.Message); + } + } + + public async Task CheckFileExistence(string fileKey) + { + try + { + var response = await _s3AmazonClient.GetObjectMetadataAsync(_bucketName, fileKey); + return response.IsSuccessStatusCode(); + } + catch (Exception) + { + return false; + } + } + + public async Task DeleteFileAsync(string fileKey) + { + try + { + var response = await _s3AmazonClient.DeleteObjectAsync(_bucketName, fileKey); + return response.IsSuccessStatusCode() + ? Result.Success() + : Result.Failed($"Не удалось удалить файл. Код ответа хранилища: {(int)response.HttpStatusCode}"); + } + catch (Exception e) + { + return Result.Failed(e.Message); + } + } + + private async Task GetFileStream(string bucketName, string fileKey) + => await _s3AmazonClient.GetObjectStreamAsync(bucketName, fileKey, null); + + private PutObjectRequest CreateUploadRequest(UploadFileToS3Dto uploadFileToS3Dto) + { + var contentType = uploadFileToS3Dto.ContentType; + // Для нормального отображения кириллицы в файлах + if (contentType.StartsWith("text/")) + contentType += "; charset=utf-8"; + + return new PutObjectRequest + { + BucketName = _bucketName, + Key = uploadFileToS3Dto.ExternalKey, + InputStream = uploadFileToS3Dto.FileStream, + ContentType = contentType, + DisableDefaultChecksumValidation = true, + Metadata = { [UploaderIdMetadataKey] = uploadFileToS3Dto.UploaderId } + }; + } + + private async Task FetchFilesInfoByPrefix(string prefix) + => await _s3AmazonClient.ListObjectsV2Async( + new ListObjectsV2Request + { + BucketName = _bucketName, + Prefix = prefix + }); + + private static bool IsOwner(MetadataCollection metadata, string userId) + => metadata[$"{AwsMetaDataPrefix}{UploaderIdMetadataKey}"] == userId; + + private async Task GetFileMetadataAsync(string fileKey) + { + var metadataResponse = await _s3AmazonClient.GetObjectMetadataAsync(new GetObjectMetadataRequest + { + BucketName = _bucketName, + Key = fileKey + }); + + return metadataResponse.Metadata; + } +} + + + +internal class LocalTestingS3FilesService : IS3FilesService +{ + public Task UploadFileAsync(UploadFileToS3Dto uploadFileToS3Dto) => Task.FromResult(Result.Success()); + + public Task> GetBucketFilesAsync(string bucketName, string filePathPattern) => Task.FromResult(new List()); + + public Task> GetDownloadUrl(string fileKey) => Task.FromResult(Result.Success("download")); + + public Task CheckFileExistence(string fileKey) => Task.FromResult(true); + + public Task DeleteFileAsync(string fileKey) => Task.FromResult(Result.Success()); +} \ No newline at end of file diff --git a/HwProj.ContentService/HwProj.ContentService.API/appsettings.json b/HwProj.ContentService/HwProj.ContentService.API/appsettings.json index 21b89e6c2..de0b9bc31 100644 --- a/HwProj.ContentService/HwProj.ContentService.API/appsettings.json +++ b/HwProj.ContentService/HwProj.ContentService.API/appsettings.json @@ -1,18 +1,25 @@ { + "ConnectionStrings": { + "DefaultConnectionForWindows": "Server=(localdb)\\mssqllocaldb;Database=ContentServiceDB;Trusted_Connection=True;TrustServerCertificate=true;", + "DefaultConnectionForLinux": "Server=localhost,1433;Database=ContentServiceDB;User ID=SA;Password=password_1234;" + }, "Logging": { "LogLevel": { - "Default": "Warning" + "Default": "Information" } }, "AllowedHosts": "*", - "StorageClientConfiguration": { + "ExternalStorageConfiguration": { "AccessKeyId": "abc", "SecretKey": "efg", "Region": "us-east-1", "ServiceURL": "https://storage.yandexcloud.net", "DefaultBucketName": "users-content-bucket" }, - "ServiceName": "Content API", + "LocalStorageConfiguration": { + "Path": "/app/data/" + }, + "ServiceName": "Content API", "Services": { "Auth": "http://localhost:5001", "Courses": "http://localhost:5002", diff --git a/HwProj.ContentService/HwProj.ContentService.Client/ContentServiceClient.cs b/HwProj.ContentService/HwProj.ContentService.Client/ContentServiceClient.cs index 625eaff6d..25bc9a29d 100644 --- a/HwProj.ContentService/HwProj.ContentService.Client/ContentServiceClient.cs +++ b/HwProj.ContentService/HwProj.ContentService.Client/ContentServiceClient.cs @@ -1,12 +1,14 @@ using System; using System.Net.Http; using System.Net.Http.Headers; +using System.Text; using System.Threading.Tasks; using HwProj.HttpUtils; using HwProj.Models.ContentService.DTO; using HwProj.Models.Result; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; +using Newtonsoft.Json; namespace HwProj.ContentService.Client { @@ -24,54 +26,98 @@ public ContentServiceClient(IHttpClientFactory clientFactory, IHttpContextAccess _contentServiceUri = new Uri(configuration.GetSection("Services")["Content"]); } - public async Task UploadFileAsync(UploadFileDTO uploadFileDto) + public async Task ProcessFilesAsync(ProcessFilesDTO processFilesDto) { using var httpRequest = new HttpRequestMessage( HttpMethod.Post, - _contentServiceUri + "api/Files/upload"); + _contentServiceUri + "api/Files/process"); var multipartContent = new MultipartFormDataContent(); - multipartContent.Add(new StringContent(uploadFileDto.CourseId.ToString()), "courseId"); - multipartContent.Add(new StringContent(uploadFileDto.HomeworkId.ToString()), "homeworkId"); + multipartContent.Add(new StringContent(processFilesDto.FilesScope.CourseId.ToString()), + "FilesScope.CourseId"); + multipartContent.Add(new StringContent(processFilesDto.FilesScope.CourseUnitType), + "FilesScope.CourseUnitType"); + multipartContent.Add(new StringContent(processFilesDto.FilesScope.CourseUnitId.ToString()), + "FilesScope.CourseUnitId"); - var fileStreamContent = new StreamContent(uploadFileDto.File.OpenReadStream()); - fileStreamContent.Headers.ContentType = MediaTypeHeaderValue.Parse(uploadFileDto.File.ContentType); - multipartContent.Add(fileStreamContent, "file", uploadFileDto.File.FileName); + // Добавляем идентификаторы файлов, подлежащих удалению + foreach (var fileId in processFilesDto.DeletingFileIds) + multipartContent.Add(new StringContent(fileId.ToString()), "deletingFileIds"); + + // Добавляем все файлы + foreach (var file in processFilesDto.NewFiles) + { + var fileStreamContent = new StreamContent(file.OpenReadStream()); + fileStreamContent.Headers.ContentType = MediaTypeHeaderValue.Parse(file.ContentType); + multipartContent.Add(fileStreamContent, "newFiles", file.FileName); + } httpRequest.Content = multipartContent; httpRequest.TryAddUserId(_httpContextAccessor); try { - var response = await _httpClient.SendAsync(httpRequest); - return await response.DeserializeAsync(); + await _httpClient.SendAsync(httpRequest); + return Result.Success(); } catch (HttpRequestException e) { - return Result.Failed("Пока не можем сохранить файлы. Попробуйте повторить позже"); + return Result.Failed( + "Пока не можем обработать файлы. \nПожалуйста, попробуйте повторить позже"); } } - public async Task> GetDownloadLinkAsync(string fileKey) + public async Task> GetFilesStatuses(ScopeDTO scopeDto) { - var encodedFileKey = Uri.EscapeDataString(fileKey); using var httpRequest = new HttpRequestMessage( - HttpMethod.Get, - _contentServiceUri + $"api/Files/downloadLink?key={encodedFileKey}"); + HttpMethod.Post, + _contentServiceUri + "api/Files/statuses") + { + Content = new StringContent( + JsonConvert.SerializeObject(scopeDto), + Encoding.UTF8, + "application/json") + }; - var response = await _httpClient.SendAsync(httpRequest); - return await response.DeserializeAsync>(); + try + { + var response = await _httpClient.SendAsync(httpRequest); + var filesStatuses = await response.DeserializeAsync(); + return Result.Success(filesStatuses); + } + catch (HttpRequestException e) + { + return Result.Failed( + "Пока не можем получить информацию о файлах. \nВсе ваши данные сохранены — попробуйте повторить позже"); + } } - - public async Task> GetFilesInfo(long courseId, long? homeworkId = null) + + public async Task> GetDownloadLinkAsync(long fileId) { - var url = _contentServiceUri + $"api/Files/filesInfo/{courseId}"; - if (homeworkId.HasValue) + using var httpRequest = new HttpRequestMessage( + HttpMethod.Get, + _contentServiceUri + $"api/Files/downloadLink?fileId={fileId}"); + + try { - url += $"?homeworkId={homeworkId.Value}"; + var response = await _httpClient.SendAsync(httpRequest); + var result = await response.DeserializeAsync(); + + return Result.Success(result); } + catch (HttpRequestException e) + { + return Result.Failed( + "Пока не можем открыть файл. \nВсе ваши данные сохранены — попробуйте повторить позже"); + } + } + public async Task> GetFilesInfo(long courseId, bool uploadedOnly, string courseUnitType) + { + var url = _contentServiceUri + + $"api/Files/info/course/{courseId}?uploadedOnly={uploadedOnly}&courseUnitType={courseUnitType}"; using var httpRequest = new HttpRequestMessage(HttpMethod.Get, url); + try { var response = await _httpClient.SendAsync(httpRequest); @@ -80,21 +126,44 @@ public async Task> GetFilesInfo(long courseId, long? homew } catch (HttpRequestException e) { - return Result.Failed("Пока не можем получить информацию о файлах. " + - "\nВсе ваши данные сохранены — попробуйте повторить позже"); + return Result.Failed( + "Пока не можем получить информацию о файлах. \nВсе ваши данные сохранены — попробуйте повторить позже"); } } - - public async Task DeleteFileAsync(string fileKey) + + public async Task TransferFilesFromCourse(CourseFilesTransferDto filesTransfer) { - var encodedFileKey = Uri.EscapeDataString(fileKey); - using var httpRequest = new HttpRequestMessage( - HttpMethod.Delete, - _contentServiceUri + $"api/Files?key={encodedFileKey}"); - httpRequest.TryAddUserId(_httpContextAccessor); + var url = _contentServiceUri + "api/Files/transfer"; + using var httpRequest = new HttpRequestMessage(HttpMethod.Post, url) + { + Content = new StringContent( + JsonConvert.SerializeObject(filesTransfer), + Encoding.UTF8, + "application/json") + }; + + try + { + await _httpClient.SendAsync(httpRequest); + return Result.Success(); + } + catch (HttpRequestException e) + { + return Result.Failed("Не удалось перенести информацию о файлах — попробуйте повторить позже"); + } + } - var response = await _httpClient.SendAsync(httpRequest); - return await response.DeserializeAsync(); + public async Task Ping() + { + try + { + await _httpClient.GetAsync(_contentServiceUri + "api/system/ping"); + return true; + } + catch + { + return false; + } } } -} \ No newline at end of file +} diff --git a/HwProj.ContentService/HwProj.ContentService.Client/IContentServiceClient.cs b/HwProj.ContentService/HwProj.ContentService.Client/IContentServiceClient.cs index 6186debe6..3a1264862 100644 --- a/HwProj.ContentService/HwProj.ContentService.Client/IContentServiceClient.cs +++ b/HwProj.ContentService/HwProj.ContentService.Client/IContentServiceClient.cs @@ -6,12 +6,11 @@ namespace HwProj.ContentService.Client { public interface IContentServiceClient { - Task UploadFileAsync(UploadFileDTO uploadFileDto); - - Task> GetDownloadLinkAsync(string fileKey); - - Task> GetFilesInfo(long courseId, long? homeworkId = null); - - Task DeleteFileAsync(string fileKey); + Task ProcessFilesAsync(ProcessFilesDTO processFilesDto); + Task> GetFilesStatuses(ScopeDTO scopeDto); + Task> GetDownloadLinkAsync(long fileId); + Task> GetFilesInfo(long courseId, bool uploadedOnly, string courseUnitType); + Task TransferFilesFromCourse(CourseFilesTransferDto filesTransfer); + Task Ping(); } -} \ No newline at end of file +} diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/ApplicationProfile.cs b/HwProj.CoursesService/HwProj.CoursesService.API/ApplicationProfile.cs index 4874e0d88..c57a959e1 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/ApplicationProfile.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/ApplicationProfile.cs @@ -17,7 +17,7 @@ public ApplicationProfile() CreateMap(); CreateMap().ReverseMap(); - CreateMap().ReverseMap(); + CreateMap().ReverseMap(); CreateMap(); CreateMap(); diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/CoursesController.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/CoursesController.cs index 18503d91e..a6f4cb0d6 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/CoursesController.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/CoursesController.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Threading.Tasks; using AutoMapper; using HwProj.CoursesService.API.Filters; @@ -10,9 +9,7 @@ using Microsoft.AspNetCore.Mvc; using System.Linq; using System.Net; -using HwProj.AuthService.Client; using HwProj.CoursesService.API.Repositories; -using HwProj.Models.AuthService.DTO; using HwProj.Models.CoursesService.DTO; using Microsoft.EntityFrameworkCore; using HwProj.CoursesService.API.Domains; @@ -28,16 +25,13 @@ public class CoursesController : Controller private readonly ICoursesService _coursesService; private readonly ICourseFilterService _courseFilterService; private readonly IHomeworksRepository _homeworksRepository; - private readonly IMapper _mapper; public CoursesController(ICoursesService coursesService, IHomeworksRepository homeworksRepository, - IMapper mapper, ICourseFilterService courseFilterService) { _coursesService = coursesService; _homeworksRepository = homeworksRepository; - _mapper = mapper; _courseFilterService = courseFilterService; } @@ -49,6 +43,17 @@ public async Task GetAll() return courses; } + [CourseDataFilter] + [HttpGet("view/{courseId}")] + public async Task GetView(long courseId) + { + var userId = Request.GetUserIdFromHeader(); + var course = await _coursesService.GetAsync(courseId, userId, true); + if (course == null) return NotFound(); + + return Ok(course); + } + [CourseDataFilter] [HttpGet("{courseId}")] public async Task Get(long courseId) @@ -106,7 +111,7 @@ public async Task AddCourse([FromBody] CreateCourseViewModel cour } var courseId = await _coursesService.AddAsync(courseViewModel, baseCourse, mentorId); - + return Ok(courseId); } @@ -189,17 +194,6 @@ public async Task AcceptLecturer(long courseId, [FromQuery] strin return Ok(); } - [HttpGet("getLecturersAvailableForCourse/{courseId}")] - [ProducesResponseType(typeof(AccountDataDto[]), (int)HttpStatusCode.OK)] - public async Task GetLecturersAvailableForCourse(long courseId) - { - var mentorId = Request.GetMentorId(); - var result = await _coursesService.GetLecturersAvailableForCourse(courseId, mentorId); - return result == null - ? NotFound() as IActionResult - : Ok(result); - } - [HttpGet("getCourseLecturers/{courseId}")] [ProducesResponseType(typeof(string[]), (int)HttpStatusCode.OK)] public async Task GetCourseLecturersIds(long courseId) diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/HomeworksController.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/HomeworksController.cs index cfde5cf8f..dbbdb1ba6 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/HomeworksController.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/HomeworksController.cs @@ -5,7 +5,6 @@ using HwProj.Models.CoursesService.ViewModels; using Microsoft.AspNetCore.Mvc; using System.Linq; -using HwProj.Models; namespace HwProj.CoursesService.API.Controllers { @@ -28,9 +27,8 @@ public async Task AddHomework(long courseId, var validationResult = Validator.ValidateHomework(homeworkViewModel); if (validationResult.Any()) return BadRequest(validationResult); - var homework = homeworkViewModel.ToHomework(); - var homeworkId = await _homeworksService.AddHomeworkAsync(courseId, homework); - return Ok(homeworkId); + var newHomework = await _homeworksService.AddHomeworkAsync(courseId, homeworkViewModel); + return Ok(newHomework.ToHomeworkViewModel()); } [HttpGet("get/{homeworkId}")] @@ -66,9 +64,7 @@ public async Task UpdateHomework(long homeworkId, var validationResult = Validator.ValidateHomework(homeworkViewModel, homework); if (validationResult.Any()) return BadRequest(validationResult); - var updatedHomework = - await _homeworksService.UpdateHomeworkAsync(homeworkId, homeworkViewModel.ToHomework(), - homeworkViewModel.ActionOptions ?? ActionOptions.Default); + var updatedHomework = await _homeworksService.UpdateHomeworkAsync(homeworkId, homeworkViewModel); return Ok(updatedHomework.ToHomeworkViewModel()); } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/TasksController.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/TasksController.cs index bb8af9cf2..e8b8ec613 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/TasksController.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/TasksController.cs @@ -1,16 +1,15 @@ -using System; -using System.Linq; -using System.Threading.Tasks; using HwProj.CoursesService.API.Domains; using HwProj.CoursesService.API.Filters; using HwProj.CoursesService.API.Models; -using HwProj.CoursesService.API.Repositories; using HwProj.CoursesService.API.Services; using HwProj.Models; using HwProj.Models.CoursesService.ViewModels; +using HwProj.Models.Roles; using HwProj.Utils.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; +using System; +using System.Linq; +using System.Threading.Tasks; namespace HwProj.CoursesService.API.Controllers { @@ -20,62 +19,59 @@ public class TasksController : Controller { private readonly ITasksService _tasksService; private readonly IHomeworksService _homeworksService; - private readonly ITaskQuestionsRepository _questionsRepository; + private readonly ITaskQuestionsService _taskQuestionsService; private readonly ICoursesService _coursesService; public TasksController(ITasksService tasksService, ICoursesService coursesService, - IHomeworksService homeworksService, ITaskQuestionsRepository questionsRepository) + IHomeworksService homeworksService, ITaskQuestionsService taskQuestionsService) { _tasksService = tasksService; _coursesService = coursesService; _homeworksService = homeworksService; - _questionsRepository = questionsRepository; + _taskQuestionsService = taskQuestionsService; } [HttpGet("get/{taskId}")] - public async Task GetTask(long taskId) + public async Task GetTask(long taskId, [FromQuery] bool withCriteria) { - var taskFromDb = await _tasksService.GetTaskAsync(taskId); - if (taskFromDb == null) return NotFound(); + var task = await _tasksService.GetTaskAsync(taskId, withCriteria); + if (task == null) return NotFound(); - if (taskFromDb.PublicationDate > DateTime.UtcNow) + if (task.PublicationDate > DateTime.UtcNow) { var userId = Request.GetUserIdFromHeader(); - var homework = taskFromDb.Homework; + var homework = await _homeworksService.GetHomeworkAsync(task.HomeworkId); var lecturers = await _coursesService.GetCourseLecturers(homework.CourseId); if (!lecturers.Contains(userId)) return BadRequest(); } - - var task = taskFromDb.ToHomeworkTaskViewModel(); - return Ok(task); + return Ok(task.ToHomeworkTaskViewModel()); } [HttpGet("getForEditing/{taskId}")] [ServiceFilter(typeof(CourseMentorOnlyAttribute))] public async Task GetForEditingTask(long taskId) { - var taskFromDb = await _tasksService.GetForEditingTaskAsync(taskId); + var task = await _tasksService.GetForEditingTaskAsync(taskId); - if (taskFromDb == null) + if (task == null) { return NotFound(); } - var task = taskFromDb.ToHomeworkTaskForEditingViewModel(); - return Ok(task); + return Ok(task.ToHomeworkTaskForEditingViewModel()); } [HttpPost("add/{homeworkId}")] [ServiceFilter(typeof(CourseMentorOnlyAttribute))] - public async Task AddTask(long homeworkId, [FromBody] CreateTaskViewModel taskViewModel) + public async Task AddTask(long homeworkId, [FromBody] PostTaskViewModel taskViewModel) { var homework = await _homeworksService.GetHomeworkAsync(homeworkId); var validationResult = Validator.ValidateTask(taskViewModel, homework); if (validationResult.Any()) return BadRequest(validationResult); - var taskId = await _tasksService.AddTaskAsync(homeworkId, taskViewModel.ToHomeworkTask()); + var task = await _tasksService.AddTaskAsync(homeworkId, taskViewModel); - return Ok(taskId); + return Ok(task); } [HttpDelete("delete/{taskId}")] //bug with rights @@ -87,7 +83,7 @@ public async Task DeleteTask(long taskId) [HttpPut("update/{taskId}")] [ServiceFilter(typeof(CourseMentorOnlyAttribute))] - public async Task UpdateTask(long taskId, [FromBody] CreateTaskViewModel taskViewModel) + public async Task UpdateTask(long taskId, [FromBody] PostTaskViewModel taskViewModel) { var previousState = await _tasksService.GetForEditingTaskAsync(taskId); var validationResult = Validator.ValidateTask(taskViewModel, @@ -96,7 +92,7 @@ public async Task UpdateTask(long taskId, [FromBody] CreateTaskVi if (validationResult.Any()) return BadRequest(validationResult); var updatedTask = - await _tasksService.UpdateTaskAsync(taskId, taskViewModel.ToHomeworkTask(), + await _tasksService.UpdateTaskAsync(taskId, taskViewModel, taskViewModel.ActionOptions ?? ActionOptions.Default); return Ok(updatedTask.ToHomeworkTaskViewModel()); } @@ -114,7 +110,7 @@ public async Task AddQuestionForTask([FromBody] AddTaskQuestionDt if (!await _coursesService.HasStudent(task.Homework.CourseId, studentId)) return Forbid(); - await _questionsRepository.AddAsync(new TaskQuestion + await _taskQuestionsService.AddQuestionAsync(new TaskQuestion { TaskId = task.Id, StudentId = studentId, @@ -137,10 +133,11 @@ public async Task GetQuestionsForTask(long taskId) if (!isLecturer && !isStudent) return Forbid(); - var questions = _questionsRepository.FindAll(x => x.TaskId == taskId); - questions = isLecturer ? questions : questions.Where(x => !x.IsPrivate || x.StudentId == userId); + var questions = isLecturer + ? await _taskQuestionsService.GetQuestionsForLecturerAsync(taskId) + : await _taskQuestionsService.GetStudentQuestionsAsync(taskId, userId); - var result = (await questions.ToListAsync()).Select(x => new GetTaskQuestionDto + var result = questions.Select(x => new GetTaskQuestionDto { Id = x.Id, StudentId = x.StudentId, @@ -152,8 +149,40 @@ public async Task GetQuestionsForTask(long taskId) return Ok(result); } + [HttpGet("openQuestions")] + public async Task GetOpenQuestions() + { + var userId = Request.GetUserIdFromHeader(); + var courses = await _coursesService.GetUserCoursesAsync(userId, Roles.LecturerRole); + + var tasks = courses + .Where(x => x.IsOpen) + .SelectMany(x => x.Homeworks.SelectMany(h => h.Tasks)) + .ToDictionary(t => t.Id); + + var taskIds = tasks.Keys.ToArray(); + var questions = await _taskQuestionsService.GetQuestionsForLecturerAsync(taskIds); + + var result = questions + .Where(x => x.Answer == null) + .GroupBy(x => x.TaskId) + .Select(x => + { + var task = tasks[x.Key]; + return new QuestionsSummary + { + TaskId = x.Key, + TaskTitle = task.Title, + Count = x.Count() + }; + }) + .ToArray(); + + return Ok(result); + } + [HttpPost("addAnswer")] - public async Task GetQuestionsForTask(AddAnswerForQuestionDto answer) + public async Task AddAnswerForQuestion(AddAnswerForQuestionDto answer) { if (string.IsNullOrEmpty(answer.Answer)) return BadRequest("Текст ответа пуст"); @@ -161,7 +190,7 @@ public async Task GetQuestionsForTask(AddAnswerForQuestionDto ans var lecturerId = Request.GetUserIdFromHeader(); if (lecturerId == null) return NotFound(); - var question = await _questionsRepository.FindAsync(x => x.Id == answer.QuestionId); + var question = await _taskQuestionsService.GetQuestionAsync(answer.QuestionId); if (question == null) return NotFound(); var task = await _tasksService.GetTaskAsync(question.TaskId); @@ -171,11 +200,7 @@ public async Task GetQuestionsForTask(AddAnswerForQuestionDto ans var isLecturer = (await _coursesService.GetCourseLecturers(courseId)).Contains(lecturerId); if (!isLecturer) return Forbid(); - await _questionsRepository.UpdateAsync(question.Id, x => new TaskQuestion - { - LecturerId = lecturerId, - Answer = answer.Answer - }); + await _taskQuestionsService.AddAnswerAsync(question.Id, lecturerId, answer.Answer); return Ok(); } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Dockerfile b/HwProj.CoursesService/HwProj.CoursesService.API/Dockerfile index 830a056a4..418440968 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Dockerfile +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Dockerfile @@ -9,7 +9,9 @@ COPY ["HwProj.EventBus/HwProj.EventBus.Client/", "HwProj.EventBus/HwProj.EventBu COPY ["HwProj.Common/HwProj.Models/", "HwProj.Common/HwProj.Models/"] COPY ["HwProj.Common/HwProj.Repositories/", "HwProj.Common/HwProj.Repositories/"] COPY ["HwProj.AuthService/HwProj.AuthService.Client/", "HwProj.AuthService/HwProj.AuthService.Client/"] +COPY ["HwProj.ContentService/HwProj.ContentService.Client/", "HwProj.ContentService/HwProj.ContentService.Client/"] COPY ["HwProj.Common/HwProj.HttpUtils/", "HwProj.Common/HwProj.HttpUtils/"] +COPY ["HwProj.NotificationsService/HwProj.NotificationService.Events/", "HwProj.NotificationsService/HwProj.NotificationService.Events/"] WORKDIR "/src/HwProj.CoursesService/HwProj.CoursesService.API" RUN dotnet publish "HwProj.CoursesService.API.csproj" -c Release -o /app/publish diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Domains/MappingExtensions.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Domains/MappingExtensions.cs index bfef52d02..6dfea46bb 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Domains/MappingExtensions.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Domains/MappingExtensions.cs @@ -1,20 +1,22 @@ -using System.Linq; +using System.Linq; using HwProj.CoursesService.API.Models; using HwProj.Models.CoursesService.ViewModels; using System; using HwProj.Models.CoursesService; using HwProj.Models.CoursesService.DTO; using Microsoft.EntityFrameworkCore.Internal; +using CriterionType = HwProj.Models.CoursesService.ViewModels.CriterionType; namespace HwProj.CoursesService.API.Domains { public static class MappingExtensions { private static readonly DateTime DateToOverride = DateTime.MaxValue; + private static readonly StringSplitOptions splitOptions = StringSplitOptions.RemoveEmptyEntries; public static HomeworkViewModel ToHomeworkViewModel(this Homework homework) { - var tags = homework.Tags?.Split(';') ?? Array.Empty(); + var tags = homework.Tags?.Split(';', splitOptions) ?? Array.Empty(); return new HomeworkViewModel() { Id = homework.Id, @@ -36,7 +38,7 @@ public static HomeworkViewModel ToHomeworkViewModel(this Homework homework) public static HomeworkTaskViewModel ToHomeworkTaskViewModel(this HomeworkTask task) { - var tags = task.Homework.Tags?.Split(';') ?? Array.Empty(); + var tags = task.Homework.Tags?.Split(';', splitOptions) ?? Array.Empty(); var evaluatedPublicationDate = task.PublicationDate ?? task.Homework.PublicationDate; return new HomeworkTaskViewModel() { @@ -54,6 +56,14 @@ public static HomeworkTaskViewModel ToHomeworkTaskViewModel(this HomeworkTask ta IsGroupWork = tags.Contains(HomeworkTags.GroupWork), HomeworkId = task.HomeworkId, Tags = tags, + Criteria = task.Criteria.Select(c => new CriterionViewModel + { + Id = c.Id, + Type = (CriterionType)c.Type, + Name = c.Name, + MaxPoints = c.MaxPoints + }) + .ToList(), }; } @@ -73,7 +83,7 @@ public static CourseMateViewModel ToCourseMateViewModel(this CourseMate courseMa ? new StudentCharacteristicsDto() { Description = characteristics.Description, - Tags = characteristics.Tags.Split(";", StringSplitOptions.RemoveEmptyEntries), + Tags = characteristics.Tags.Split(';', splitOptions), } : null }; @@ -85,7 +95,7 @@ public static CourseDTO ToCourseDto(this Course course) Name = course.Name, GroupName = course.GroupName, IsCompleted = course.IsCompleted, - MentorIds = course.Mentors.Select(x => x.UserId).ToArray(), + MentorIds = course.Mentors.Select(m => m.UserId).ToArray(), IsOpen = course.IsOpen, InviteCode = course.InviteCode, CourseMates = course.CourseMates.Select(cm => cm.ToCourseMateViewModel()).ToArray(), @@ -99,19 +109,28 @@ public static CoursePreview ToCoursePreview(this Course course) Name = course.Name, GroupName = course.GroupName, IsCompleted = course.IsCompleted, - MentorIds = course.Mentors.Select(x => x.UserId).ToArray(), + MentorIds = course.Mentors.Select(m => m.UserId).ToArray(), }; - public static HomeworkTask ToHomeworkTask(this CreateTaskViewModel createTaskViewModel) + public static Criterion ToCriterion(this CriterionViewModel criterion) => new Criterion + { + Id = criterion.Id, + Type = (Models.CriterionType)criterion.Type, + Name = criterion.Name, + MaxPoints = criterion.MaxPoints + }; + + public static HomeworkTask ToHomeworkTask(this PostTaskViewModel postTaskViewModel) => new HomeworkTask() { - Title = createTaskViewModel.Title, - Description = createTaskViewModel.Description, - MaxRating = createTaskViewModel.MaxRating, - HasDeadline = createTaskViewModel.HasDeadline, - DeadlineDate = createTaskViewModel.DeadlineDate, - IsDeadlineStrict = createTaskViewModel.IsDeadlineStrict, - PublicationDate = createTaskViewModel.PublicationDate, + Title = postTaskViewModel.Title, + Description = postTaskViewModel.Description, + MaxRating = postTaskViewModel.MaxRating, + HasDeadline = postTaskViewModel.HasDeadline, + DeadlineDate = postTaskViewModel.DeadlineDate, + IsDeadlineStrict = postTaskViewModel.IsDeadlineStrict, + PublicationDate = postTaskViewModel.PublicationDate, + Criteria = postTaskViewModel.Criteria.Select(x => x.ToCriterion()).ToList(), }; public static Homework ToHomework(this CreateHomeworkViewModel createHomeworkViewModel) @@ -131,7 +150,7 @@ public static CourseTemplate ToCourseTemplate(this CreateCourseViewModel createC => new CourseTemplate() { Name = createCourseViewModel.Name, - GroupName = createCourseViewModel.GroupName, + GroupName = string.Join(", ", createCourseViewModel.GroupNames), IsOpen = createCourseViewModel.IsOpen, }; diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Domains/Validations.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Domains/Validations.cs index e35753444..2a4dda861 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Domains/Validations.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Domains/Validations.cs @@ -8,7 +8,7 @@ namespace HwProj.CoursesService.API.Domains { public static class Validator { - public static List ValidateTask(CreateTaskViewModel task, Homework homework, + public static List ValidateTask(PostTaskViewModel task, Homework homework, HomeworkTask? previousState = null) { var errors = new List(); @@ -63,6 +63,7 @@ public static List ValidateTask(CreateTaskViewModel task, Homework homew } if (task.DeadlineDate is null && task.PublicationDate is { } publicationDate && + publicationDate != DateTime.MaxValue && publicationDate > homework.DeadlineDate) { errors.Add("Дедлайн задачи, который непереопределен от домашнего задания раньше чем дата публикации самой задачи"); diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/HwProj.CoursesService.API.csproj b/HwProj.CoursesService/HwProj.CoursesService.API/HwProj.CoursesService.API.csproj index ef718c9b4..b3e05e585 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/HwProj.CoursesService.API.csproj +++ b/HwProj.CoursesService/HwProj.CoursesService.API/HwProj.CoursesService.API.csproj @@ -22,9 +22,11 @@ + + \ No newline at end of file diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/20251230213439_Criteria.Designer.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/20251230213439_Criteria.Designer.cs new file mode 100644 index 000000000..2e1d1382d --- /dev/null +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/20251230213439_Criteria.Designer.cs @@ -0,0 +1,356 @@ +// +using System; +using HwProj.CoursesService.API.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace HwProj.CoursesService.API.Migrations +{ + [DbContext(typeof(CourseContext))] + [Migration("20251230213439_Criteria")] + partial class Criteria + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.Assignment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("CourseId"); + + b.Property("MentorId"); + + b.Property("StudentId"); + + b.HasKey("Id"); + + b.HasIndex("CourseId"); + + b.ToTable("Assignments"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.Course", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("GroupName"); + + b.Property("InviteCode"); + + b.Property("IsCompleted"); + + b.Property("IsOpen"); + + b.Property("MentorIds"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("Courses"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.CourseFilter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("FilterJson"); + + b.HasKey("Id"); + + b.ToTable("CourseFilters"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.CourseMate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("CourseId"); + + b.Property("IsAccepted"); + + b.Property("StudentId"); + + b.HasKey("Id"); + + b.HasIndex("CourseId"); + + b.ToTable("CourseMates"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.Criterion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("MaxPoints"); + + b.Property("Name"); + + b.Property("TaskId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("TaskId"); + + b.ToTable("Criteria"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("CourseId"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.GroupMate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("GroupId"); + + b.Property("StudentId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasAlternateKey("GroupId", "StudentId"); + + b.ToTable("GroupMates"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.Homework", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("CourseId"); + + b.Property("DeadlineDate"); + + b.Property("Description"); + + b.Property("HasDeadline"); + + b.Property("IsDeadlineStrict"); + + b.Property("PublicationDate"); + + b.Property("Tags"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("CourseId"); + + b.ToTable("Homeworks"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.HomeworkTask", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("DeadlineDate"); + + b.Property("Description"); + + b.Property("HasDeadline"); + + b.Property("HomeworkId"); + + b.Property("IsDeadlineStrict"); + + b.Property("MaxRating"); + + b.Property("PublicationDate"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("HomeworkId"); + + b.ToTable("Tasks"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.StudentCharacteristics", b => + { + b.Property("CourseMateId"); + + b.Property("Description"); + + b.Property("Tags"); + + b.HasKey("CourseMateId"); + + b.ToTable("StudentCharacteristics"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.TaskModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("GroupId"); + + b.Property("TaskId"); + + b.HasKey("Id"); + + b.HasIndex("GroupId"); + + b.ToTable("TasksModels"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.TaskQuestion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Answer") + .HasMaxLength(1000); + + b.Property("IsPrivate"); + + b.Property("LecturerId"); + + b.Property("StudentId"); + + b.Property("TaskId"); + + b.Property("Text") + .HasMaxLength(1000); + + b.HasKey("Id"); + + b.HasIndex("TaskId"); + + b.ToTable("Questions"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.UserToCourseFilter", b => + { + b.Property("CourseId"); + + b.Property("UserId"); + + b.Property("CourseFilterId"); + + b.HasKey("CourseId", "UserId"); + + b.HasIndex("CourseFilterId"); + + b.ToTable("UserToCourseFilters"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.Assignment", b => + { + b.HasOne("HwProj.CoursesService.API.Models.Course") + .WithMany("Assignments") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.CourseMate", b => + { + b.HasOne("HwProj.CoursesService.API.Models.Course") + .WithMany("CourseMates") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.Criterion", b => + { + b.HasOne("HwProj.CoursesService.API.Models.HomeworkTask", "Task") + .WithMany("Criteria") + .HasForeignKey("TaskId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.GroupMate", b => + { + b.HasOne("HwProj.CoursesService.API.Models.Group") + .WithMany("GroupMates") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.Homework", b => + { + b.HasOne("HwProj.CoursesService.API.Models.Course") + .WithMany("Homeworks") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.HomeworkTask", b => + { + b.HasOne("HwProj.CoursesService.API.Models.Homework", "Homework") + .WithMany("Tasks") + .HasForeignKey("HomeworkId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.StudentCharacteristics", b => + { + b.HasOne("HwProj.CoursesService.API.Models.CourseMate") + .WithOne("Characteristics") + .HasForeignKey("HwProj.CoursesService.API.Models.StudentCharacteristics", "CourseMateId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.TaskModel", b => + { + b.HasOne("HwProj.CoursesService.API.Models.Group") + .WithMany("Tasks") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.UserToCourseFilter", b => + { + b.HasOne("HwProj.CoursesService.API.Models.CourseFilter", "CourseFilter") + .WithMany() + .HasForeignKey("CourseFilterId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/20251230213439_Criteria.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/20251230213439_Criteria.cs new file mode 100644 index 000000000..8ec08eac2 --- /dev/null +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/20251230213439_Criteria.cs @@ -0,0 +1,44 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace HwProj.CoursesService.API.Migrations +{ + public partial class Criteria : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Criteria", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), + TaskId = table.Column(nullable: false), + Type = table.Column(nullable: false), + Name = table.Column(nullable: true), + MaxPoints = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Criteria", x => x.Id); + table.ForeignKey( + name: "FK_Criteria_Tasks_TaskId", + column: x => x.TaskId, + principalTable: "Tasks", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Criteria_TaskId", + table: "Criteria", + column: "TaskId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Criteria"); + } + } +} diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/CourseContextModelSnapshot.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/CourseContextModelSnapshot.cs index 26fc00997..7f4987270 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/CourseContextModelSnapshot.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/CourseContextModelSnapshot.cs @@ -1,4 +1,4 @@ -// +// using System; using HwProj.CoursesService.API.Models; using Microsoft.EntityFrameworkCore; @@ -108,6 +108,27 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("CourseMentors"); }); + modelBuilder.Entity("HwProj.CoursesService.API.Models.Criterion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("MaxPoints"); + + b.Property("Name"); + + b.Property("TaskId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("TaskId"); + + b.ToTable("Criteria"); + }); + modelBuilder.Entity("HwProj.CoursesService.API.Models.Group", b => { b.Property("Id") @@ -295,6 +316,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade); }); + modelBuilder.Entity("HwProj.CoursesService.API.Models.Criterion", b => + { + b.HasOne("HwProj.CoursesService.API.Models.HomeworkTask", "Task") + .WithMany("Criteria") + .HasForeignKey("TaskId") + .OnDelete(DeleteBehavior.Cascade); + }); + modelBuilder.Entity("HwProj.CoursesService.API.Models.GroupMate", b => { b.HasOne("HwProj.CoursesService.API.Models.Group") diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Models/Course.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Models/Course.cs index 3efb5b4e9..e5f6af8a3 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Models/Course.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Models/Course.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using HwProj.Repositories; @@ -13,8 +12,7 @@ public class Course : IEntity public bool IsOpen { get; set; } public string InviteCode { get; set; } public bool IsCompleted { get; set; } - [Obsolete] public string MentorIds { get; set; } - public List Mentors { get; set; } = new List(); + public string MentorIds { get; set; } public List CourseMates { get; set; } = new List(); public List Homeworks { get; set; } = new List(); public List Assignments { get; set; } = new List(); diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Models/CourseContext.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Models/CourseContext.cs index ebd5e1fe5..cf973b468 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Models/CourseContext.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Models/CourseContext.cs @@ -1,4 +1,4 @@ -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; namespace HwProj.CoursesService.API.Models { @@ -16,6 +16,7 @@ public sealed class CourseContext : DbContext public DbSet CourseFilters { get; set; } public DbSet UserToCourseFilters { get; set; } public DbSet Questions { get; set; } + public DbSet Criteria { get; set; } public CourseContext(DbContextOptions options) : base(options) diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Models/Criterion.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Models/Criterion.cs new file mode 100644 index 000000000..3d67a0984 --- /dev/null +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Models/Criterion.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations.Schema; +using HwProj.Repositories; + +namespace HwProj.CoursesService.API.Models +{ + public enum CriterionType + { + Free = 0 + } + + public class Criterion : IEntity + { + public long Id { get; set; } + public HomeworkTask Task { get; set; } = null!; + [ForeignKey(nameof(Task))] + public long TaskId { get; set; } + public CriterionType Type { get; set; } + public string Name { get; set; } + public int MaxPoints { get; set; } + } +} diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Models/HomeworkTask.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Models/HomeworkTask.cs index 22f3daef4..66b2c3af7 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Models/HomeworkTask.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Models/HomeworkTask.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using HwProj.Repositories; namespace HwProj.CoursesService.API.Models @@ -22,7 +23,9 @@ public class HomeworkTask : IEntity public DateTime? PublicationDate { get; set; } public long HomeworkId { get; set; } - + public Homework Homework { get; set; } + + public List Criteria { get; set; } = new List(); } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/CoursesRepository.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/CoursesRepository.cs index 09254f343..7720f60ff 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/CoursesRepository.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/CoursesRepository.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; @@ -37,16 +37,19 @@ public override async Task FindAsync(Expression> pred .AsNoTracking() .FirstOrDefaultAsync(c => c.Id == id); - public async Task GetWithCourseMatesAndHomeworksAsync(long id) + public async Task GetWithCourseMatesAndHomeworksAsync(long id, bool withCriteria) { - var course = await Context.Set() + var query = Context.Set() + .AsNoTracking() .Include(x => x.Mentors) .Include(c => c.CourseMates) .ThenInclude(c => c.Characteristics) .Include(c => c.Homeworks) - .ThenInclude(c => c.Tasks) - .AsNoTracking() - .FirstOrDefaultAsync(c => c.Id == id); + .ThenInclude(c => c.Tasks); + + var course = withCriteria + ? await query.ThenInclude(x => x.Criteria).FirstOrDefaultAsync(c => c.Id == id) + : await query.FirstOrDefaultAsync(c => c.Id == id); // todo: перенести OrderBy в Include после обновления до EF Core 5.x course.Homeworks = course.Homeworks.OrderBy(h => h.PublicationDate).ToList(); diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/HomeworksRepository.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/HomeworksRepository.cs index 4a4138c9d..693706635 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/HomeworksRepository.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/HomeworksRepository.cs @@ -27,10 +27,12 @@ public async Task GetAllWithTasksByCourseAsync(long courseId) .ToArrayAsync(); } - public async Task GetWithTasksAsync(long id) + public async Task GetWithTasksAsync(long id, bool withCriteria = false) { - return await Context.Set().AsNoTracking().Include(h => h.Tasks) - .FirstOrDefaultAsync(h => h.Id == id); + var query = Context.Set().AsNoTracking().Include(h => h.Tasks); + return withCriteria + ? await query.ThenInclude(x => x.Criteria).FirstOrDefaultAsync(h => h.Id == id) + : await query.FirstOrDefaultAsync(h => h.Id == id); } } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/ICoursesRepository.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/ICoursesRepository.cs index 62454d974..f56c8c638 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/ICoursesRepository.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/ICoursesRepository.cs @@ -9,7 +9,7 @@ public interface ICoursesRepository : ICrudRepository { Task GetWithCourseMates(long id); Task GetWithHomeworksAsync(long id); - Task GetWithCourseMatesAndHomeworksAsync(long id); + Task GetWithCourseMatesAndHomeworksAsync(long id, bool withCriteria = false); IQueryable GetAllWithCourseMatesAndHomeworks(); } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/IHomeworksRepository.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/IHomeworksRepository.cs index 66c967996..f621269b3 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/IHomeworksRepository.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/IHomeworksRepository.cs @@ -8,6 +8,6 @@ public interface IHomeworksRepository : ICrudRepository { Task GetAllWithTasksAsync(); Task GetAllWithTasksByCourseAsync(long courseId); - Task GetWithTasksAsync(long id); + Task GetWithTasksAsync(long id, bool withCriteria = false); } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/ITaskQuestionsRepository.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/ITaskQuestionsRepository.cs index cbce7565e..0a0d1cb9c 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/ITaskQuestionsRepository.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/ITaskQuestionsRepository.cs @@ -6,12 +6,4 @@ namespace HwProj.CoursesService.API.Repositories public interface ITaskQuestionsRepository : ICrudRepository { } - - public class TaskQuestionsRepository : CrudRepository, ITaskQuestionsRepository - { - public TaskQuestionsRepository(CourseContext context) - : base(context) - { - } - } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/ITasksRepository.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/ITasksRepository.cs index 3b0959178..5d43ba77c 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/ITasksRepository.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/ITasksRepository.cs @@ -1,4 +1,7 @@ -using System.Threading.Tasks; +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Threading.Tasks; using HwProj.CoursesService.API.Models; using HwProj.Repositories; @@ -6,6 +9,8 @@ namespace HwProj.CoursesService.API.Repositories { public interface ITasksRepository : ICrudRepository { - Task GetWithHomeworkAsync(long id); + Task GetWithHomeworkAsync(long id); + Task UpdateAsync(long id, Expression> updateFunc, List criteria); + Task GetWithHomeworkAndCriteriaAsync(long id); } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/TaskQuestionsRepository.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/TaskQuestionsRepository.cs new file mode 100644 index 000000000..3b1f89aeb --- /dev/null +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/TaskQuestionsRepository.cs @@ -0,0 +1,13 @@ +using HwProj.CoursesService.API.Models; +using HwProj.Repositories; + +namespace HwProj.CoursesService.API.Repositories +{ + public class TaskQuestionsRepository : CrudRepository, ITaskQuestionsRepository + { + public TaskQuestionsRepository(CourseContext context) + : base(context) + { + } + } +} \ No newline at end of file diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/TasksRepository.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/TasksRepository.cs index baa9b6610..f998be609 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/TasksRepository.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/TasksRepository.cs @@ -1,4 +1,9 @@ -using System.Threading.Tasks; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using System.Transactions; using HwProj.CoursesService.API.Models; using HwProj.Repositories; using Microsoft.EntityFrameworkCore; @@ -12,12 +17,82 @@ public TasksRepository(CourseContext context) { } - public Task GetWithHomeworkAsync(long id) + private async Task UpdateCriteria(List criteria, long taskId) + { + var criteriaToCheck = await Context.Set() + .AsNoTracking() + .Where(x => x.TaskId == taskId) + .ToDictionaryAsync(x => x.Id, x => x); + + var criteriaToAdd = new List(); + var criteriaToUpdate = new List(); + + foreach (var criterion in criteria) + { + criterion.TaskId = taskId; + + if (criterion.Id == 0) criteriaToAdd.Add(criterion); + else if (criteriaToCheck.TryGetValue(criterion.Id, out var existingCriterion)) + { + if (!_criterionComparer.Equals(criterion, existingCriterion)) + criteriaToUpdate.Add(criterion); + + criteriaToCheck.Remove(criterion.Id); + } + } + + Context.Set().AddRange(criteriaToAdd); + Context.Set().RemoveRange(criteriaToCheck.Values); + Context.Set().UpdateRange(criteriaToUpdate); + } + + public Task GetWithHomeworkAsync(long id) { return Context.Set() .Include(x => x.Homework) .AsNoTracking() .FirstOrDefaultAsync(x => x.Id == id); } + + public async Task UpdateAsync(long id, Expression> updateFunc, + List criteria) + { + using var transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled); + + await UpdateAsync(id, updateFunc); + await UpdateCriteria(criteria, id); + + await Context.SaveChangesAsync(); + transactionScope.Complete(); + } + + + public Task GetWithHomeworkAndCriteriaAsync(long id) + { + return Context.Set() + .Include(x => x.Homework) + .Include(x => x.Criteria) + .AsNoTracking() + .FirstOrDefaultAsync(x => x.Id == id); + } + + private static readonly CriterionComparer _criterionComparer = new CriterionComparer(); + + private class CriterionComparer : IEqualityComparer + { + public bool Equals(Criterion? x, Criterion? y) + { + if (ReferenceEquals(x, y)) return true; + if (x is null) return false; + if (y is null) return false; + return x.Id == y.Id && + x.TaskId == y.TaskId && + x.Type == y.Type && + x.Name == y.Name && + x.MaxPoints == y.MaxPoints; + } + + public int GetHashCode(Criterion obj) => HashCode.Combine(obj.Id, obj.TaskId, obj.Name); + } } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Services/CourseFilterUtils.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Services/CourseFilterUtils.cs index 1dd06a3d2..9e02c9cef 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Services/CourseFilterUtils.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Services/CourseFilterUtils.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using HwProj.CoursesService.API.Models; using HwProj.Models.CoursesService; diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Services/CoursesService.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Services/CoursesService.cs index 141990b80..026e401f9 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Services/CoursesService.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Services/CoursesService.cs @@ -8,6 +8,8 @@ using HwProj.CoursesService.API.Models; using HwProj.CoursesService.API.Repositories; using HwProj.CoursesService.API.Repositories.Groups; +using HwProj.Models.ContentService.DTO; +using HwProj.ContentService.Client; using HwProj.EventBus.Client.Interfaces; using HwProj.Models.AuthService.DTO; using HwProj.Models.CoursesService.ViewModels; @@ -16,6 +18,7 @@ using HwProj.Models.Roles; using HwProj.Utils.Authorization; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Internal; namespace HwProj.CoursesService.API.Services { @@ -27,6 +30,7 @@ public class CoursesService : ICoursesService private readonly ICourseMatesRepository _courseMatesRepository; private readonly IEventBus _eventBus; private readonly IAuthServiceClient _authServiceClient; + private readonly IContentServiceClient _contentServiceClient; private readonly IGroupsRepository _groupsRepository; private readonly ICourseFilterService _courseFilterService; private readonly CourseContext _context; @@ -37,6 +41,7 @@ public CoursesService(ICoursesRepository coursesRepository, ICourseMatesRepository courseMatesRepository, IEventBus eventBus, IAuthServiceClient authServiceClient, + IContentServiceClient contentServiceClient, IGroupsRepository groupsRepository, ICourseFilterService courseFilterService, CourseContext context) @@ -47,6 +52,7 @@ public CoursesService(ICoursesRepository coursesRepository, _courseMatesRepository = courseMatesRepository; _eventBus = eventBus; _authServiceClient = authServiceClient; + _contentServiceClient = contentServiceClient; _groupsRepository = groupsRepository; _courseFilterService = courseFilterService; _context = context; @@ -67,9 +73,9 @@ public async Task GetAllAsync() return await GetAsync(task.Homework.CourseId, userId); } - public async Task GetAsync(long id, string userId = "") + public async Task GetAsync(long id, string userId = "", bool asView = false) { - var course = await _coursesRepository.GetWithCourseMatesAndHomeworksAsync(id); + var course = await _coursesRepository.GetWithCourseMatesAndHomeworksAsync(id, withCriteria: asView); if (course == null) return null; CourseDomain.FillTasksInCourses(course); @@ -99,15 +105,44 @@ public async Task AddAsync(CreateCourseViewModel courseViewModel, { var courseTemplate = courseViewModel.ToCourseTemplate(); + courseTemplate.Homeworks = + baseCourse?.Homeworks.Select(h => h.ToHomeworkTemplate()).ToList() ?? + new List(); + + using var transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled); + + var newCourse = await AddFromTemplateAsync(courseTemplate, courseViewModel.StudentIDs, mentorId); + if (baseCourse != null) { - courseTemplate.Homeworks = baseCourse.Homeworks.Select(h => h.ToHomeworkTemplate()).ToList(); + var sourceHwIds = baseCourse.Homeworks.Select(hw => hw.Id); + var targetHwIds = newCourse.Homeworks.Select(hw => hw.Id); + + var homeworksMapping = sourceHwIds + .Zip(targetHwIds, (source, target) => new ScopeMappingDto + { + Source = source, + Target = target + }).ToList(); + + if (homeworksMapping.Count > 0) + { + var result = await _contentServiceClient.TransferFilesFromCourse(new CourseFilesTransferDto + { + SourceCourseId = baseCourse.Id, + TargetCourseId = newCourse.Id, + HomeworksMapping = homeworksMapping + }); + + if (!result.Succeeded) throw new TransactionAbortedException(result.Errors.Join("\n")); + } } - return await AddFromTemplateAsync(courseTemplate, courseViewModel.StudentIDs, mentorId); + transactionScope.Complete(); + return newCourse.Id; } - public async Task AddFromTemplateAsync(CourseTemplate courseTemplate, List studentIds, + private async Task AddFromTemplateAsync(CourseTemplate courseTemplate, List studentIds, string mentorId) { using var transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled); @@ -147,7 +182,9 @@ public async Task AddFromTemplateAsync(CourseTemplate courseTemplate, List } transactionScope.Complete(); - return courseId; + + var result = await _coursesRepository.GetAsync(courseId); + return result; } public async Task DeleteAsync(long id) @@ -281,6 +318,8 @@ public async Task AcceptLecturerAsync(long courseId, string lecturerEmail, MentorId = lecturerId, MentorEmail = lecturerEmail }); + //TODO: remove + await RejectCourseMateAsync(courseId, lecturerId); } return true; @@ -309,7 +348,7 @@ await _courseMatesRepository.FindAll(x => x.CourseId == courseId && x.StudentId if (courseMate == null) return false; - var tags = string.Join(";", characteristics.Tags.Distinct()); + var tags = string.Join(";", characteristics.Tags.Where(t => !string.IsNullOrWhiteSpace(t)).Distinct()); var hasCharacteristic = courseMate.Characteristics != null; diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Services/HomeworksService.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Services/HomeworksService.cs index 0aedfc77b..76844defc 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Services/HomeworksService.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Services/HomeworksService.cs @@ -1,13 +1,13 @@ using System; using System.Linq; -using System.Linq.Expressions; using System.Threading.Tasks; using HwProj.CoursesService.API.Models; using HwProj.CoursesService.API.Repositories; using HwProj.EventBus.Client.Interfaces; -using HwProj.CoursesService.API.Events; using HwProj.CoursesService.API.Domains; using HwProj.Models; +using HwProj.Models.CoursesService.ViewModels; +using HwProj.NotificationService.Events.CoursesService; namespace HwProj.CoursesService.API.Services { @@ -25,8 +25,10 @@ public HomeworksService(IHomeworksRepository homeworksRepository, IEventBus even _coursesRepository = coursesRepository; } - public async Task AddHomeworkAsync(long courseId, Homework homework) + public async Task AddHomeworkAsync(long courseId, CreateHomeworkViewModel homeworkViewModel) { + homeworkViewModel.Tags = homeworkViewModel.Tags.Where(t => !string.IsNullOrWhiteSpace(t)).ToList(); + var homework = homeworkViewModel.ToHomework(); homework.CourseId = courseId; var course = await _coursesRepository.GetWithCourseMatesAndHomeworksAsync(courseId); @@ -37,12 +39,13 @@ public async Task AddHomeworkAsync(long courseId, Homework homework) homework.DeadlineDate)); } - return await _homeworksRepository.AddAsync(homework); + await _homeworksRepository.AddAsync(homework); + return await GetHomeworkAsync(homework.Id, withCriteria: true); } - public async Task GetHomeworkAsync(long homeworkId) + public async Task GetHomeworkAsync(long homeworkId, bool withCriteria = false) { - var homework = await _homeworksRepository.GetWithTasksAsync(homeworkId); + var homework = await _homeworksRepository.GetWithTasksAsync(homeworkId, withCriteria); CourseDomain.FillTasksInHomework(homework); @@ -60,11 +63,14 @@ public async Task DeleteHomeworkAsync(long homeworkId) await _homeworksRepository.DeleteAsync(homeworkId); } - public async Task UpdateHomeworkAsync(long homeworkId, Homework update, ActionOptions options) + public async Task UpdateHomeworkAsync(long homeworkId, CreateHomeworkViewModel homeworkViewModel) { + homeworkViewModel.Tags = homeworkViewModel.Tags.Where(t => !string.IsNullOrWhiteSpace(t)).ToList(); + var update = homeworkViewModel.ToHomework(); + var options = homeworkViewModel.ActionOptions ?? ActionOptions.Default; + var homework = await _homeworksRepository.GetAsync(homeworkId); var course = await _coursesRepository.GetWithCourseMates(homework.CourseId); - var studentIds = course!.CourseMates.Where(cm => cm.IsAccepted).Select(cm => cm.StudentId).ToArray(); if (options.SendNotification && update.PublicationDate <= DateTime.UtcNow) diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Services/ICoursesService.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Services/ICoursesService.cs index 57ae4c023..a867568ad 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Services/ICoursesService.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Services/ICoursesService.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using HwProj.CoursesService.API.Models; -using HwProj.Models.AuthService.DTO; using HwProj.Models.CoursesService.DTO; using HwProj.Models.CoursesService.ViewModels; @@ -9,7 +8,7 @@ namespace HwProj.CoursesService.API.Services public interface ICoursesService { Task GetAllAsync(); - Task GetAsync(long id, string userId = ""); + Task GetAsync(long id, string userId = "", bool asView = false); Task GetForEditingAsync(long id); Task GetByTaskAsync(long taskId, string userId); Task AddAsync(CreateCourseViewModel courseViewModel, CourseDTO? baseCourse, string mentorId); @@ -20,7 +19,6 @@ public interface ICoursesService Task RejectCourseMateAsync(long courseId, string studentId); Task GetUserCoursesAsync(string userId, string role); Task AcceptLecturerAsync(long courseId, string lecturerEmail, string lecturerId); - Task GetLecturersAvailableForCourse(long courseId, string mentorId); Task GetCourseLecturers(long courseId); Task HasStudent(long courseId, string studentId); Task UpdateStudentCharacteristics(long courseId, string studentId, StudentCharacteristicsDto characteristics); diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Services/IHomeworksService.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Services/IHomeworksService.cs index 7eba21e19..2b2460c37 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Services/IHomeworksService.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Services/IHomeworksService.cs @@ -1,19 +1,19 @@ using System.Threading.Tasks; using HwProj.CoursesService.API.Models; -using HwProj.Models; +using HwProj.Models.CoursesService.ViewModels; namespace HwProj.CoursesService.API.Services { public interface IHomeworksService { - Task AddHomeworkAsync(long courseId, Homework homework); + Task AddHomeworkAsync(long courseId, CreateHomeworkViewModel homeworkViewModel); - Task GetHomeworkAsync(long homeworkId); + Task GetHomeworkAsync(long homeworkId, bool withCriteria = false); Task GetForEditingHomeworkAsync(long homeworkId); Task DeleteHomeworkAsync(long homeworkId); - Task UpdateHomeworkAsync(long homeworkId, Homework update, ActionOptions options); + Task UpdateHomeworkAsync(long homeworkId, CreateHomeworkViewModel homeworkViewModel); } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Services/ITaskQuestionsService.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Services/ITaskQuestionsService.cs new file mode 100644 index 000000000..8d4ab53e7 --- /dev/null +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Services/ITaskQuestionsService.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using HwProj.CoursesService.API.Models; + +namespace HwProj.CoursesService.API.Services +{ + public interface ITaskQuestionsService + { + Task AddQuestionAsync(TaskQuestion taskQuestion); + Task GetQuestionAsync(long taskQuestionId); + Task> GetQuestionsForLecturerAsync(long taskId); + Task> GetQuestionsForLecturerAsync(long[] taskIds); + Task> GetStudentQuestionsAsync(long taskId, string studentId); + Task AddAnswerAsync(long questionId, string lecturerId, string answer); + } +} \ No newline at end of file diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Services/ITasksService.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Services/ITasksService.cs index 8180957c3..0f6301fa5 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Services/ITasksService.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Services/ITasksService.cs @@ -1,15 +1,16 @@ -using System.Threading.Tasks; -using HwProj.CoursesService.API.Models; +using HwProj.CoursesService.API.Models; using HwProj.Models; +using HwProj.Models.CoursesService.ViewModels; +using System.Threading.Tasks; namespace HwProj.CoursesService.API.Services { public interface ITasksService { - Task GetTaskAsync(long taskId); + Task GetTaskAsync(long taskId, bool withCriteria = false); Task GetForEditingTaskAsync(long taskId); - Task AddTaskAsync(long homeworkId, HomeworkTask task); + Task AddTaskAsync(long homeworkId, PostTaskViewModel taskViewModel); Task DeleteTaskAsync(long taskId); - Task UpdateTaskAsync(long taskId, HomeworkTask update, ActionOptions options); + Task UpdateTaskAsync(long taskId, PostTaskViewModel taskViewModel, ActionOptions options); } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Services/TaskQuestionsService.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Services/TaskQuestionsService.cs new file mode 100644 index 000000000..2b5d654a3 --- /dev/null +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Services/TaskQuestionsService.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using HwProj.CoursesService.API.Models; +using HwProj.CoursesService.API.Repositories; +using Microsoft.EntityFrameworkCore; + +namespace HwProj.CoursesService.API.Services +{ + public class TaskQuestionsService : ITaskQuestionsService + { + private readonly ITaskQuestionsRepository _taskQuestionsRepository; + + public TaskQuestionsService(ITaskQuestionsRepository taskQuestionsRepository) + { + _taskQuestionsRepository = taskQuestionsRepository; + } + + public async Task AddQuestionAsync(TaskQuestion taskQuestion) + => await _taskQuestionsRepository.AddAsync(taskQuestion); + + public async Task GetQuestionAsync(long taskQuestionId) + => await _taskQuestionsRepository.FindAsync(x => x.Id == taskQuestionId); + + public async Task> GetQuestionsForLecturerAsync(long taskId) + => await GetALlTaskQuestions(taskId).ToListAsync(); + + public Task> GetQuestionsForLecturerAsync(long[] taskIds) => + _taskQuestionsRepository.FindAll(x => taskIds.Contains(x.TaskId)).ToListAsync(); + + public Task> GetStudentQuestionsAsync(long taskId, string studentId) + { + var allQuestions = GetALlTaskQuestions(taskId); + return allQuestions.Where(x => !x.IsPrivate || x.StudentId == studentId).ToListAsync(); + } + + public async Task AddAnswerAsync(long questionId, string lecturerId, string answer) + => await _taskQuestionsRepository.UpdateAsync(questionId, x => new TaskQuestion + { + LecturerId = lecturerId, + Answer = answer + }); + + private IQueryable GetALlTaskQuestions(long taskId) + => _taskQuestionsRepository.FindAll(x => x.TaskId == taskId); + } +} \ No newline at end of file diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Services/TasksService.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Services/TasksService.cs index 8b3fdde50..8cfb362dd 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Services/TasksService.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Services/TasksService.cs @@ -1,13 +1,13 @@ -using System; -using System.Threading.Tasks; -using HwProj.CoursesService.API.Events; +using HwProj.CoursesService.API.Domains; using HwProj.CoursesService.API.Models; using HwProj.CoursesService.API.Repositories; using HwProj.EventBus.Client.Interfaces; -using HwProj.CoursesService.API.Domains; -using System.Linq; using HwProj.Models; -using Microsoft.EntityFrameworkCore; +using HwProj.Models.CoursesService.ViewModels; +using HwProj.NotificationService.Events.CoursesService; +using System; +using System.Linq; +using System.Threading.Tasks; namespace HwProj.CoursesService.API.Services { @@ -18,8 +18,8 @@ public class TasksService : ITasksService private readonly ICoursesRepository _coursesRepository; private readonly IHomeworksRepository _homeworksRepository; - public TasksService(ITasksRepository tasksRepository, IEventBus eventBus, - ICoursesRepository coursesRepository, IHomeworksRepository homeworksRepository) + public TasksService(ITasksRepository tasksRepository, IEventBus eventBus, ICoursesRepository coursesRepository, + IHomeworksRepository homeworksRepository) { _tasksRepository = tasksRepository; _homeworksRepository = homeworksRepository; @@ -27,22 +27,25 @@ public TasksService(ITasksRepository tasksRepository, IEventBus eventBus, _coursesRepository = coursesRepository; } - public async Task GetTaskAsync(long taskId) + public async Task GetTaskAsync(long taskId, bool withCriteria = false) { - var task = await _tasksRepository.GetWithHomeworkAsync(taskId); + var taskFromDb = withCriteria + ? await _tasksRepository.GetWithHomeworkAndCriteriaAsync(taskId) + : await _tasksRepository.GetWithHomeworkAsync(taskId); - CourseDomain.FillTask(task.Homework, task); + CourseDomain.FillTask(taskFromDb.Homework, taskFromDb); - return task; + return taskFromDb; } public async Task GetForEditingTaskAsync(long taskId) { - return await _tasksRepository.GetWithHomeworkAsync(taskId); + return await _tasksRepository.GetWithHomeworkAndCriteriaAsync(taskId); } - public async Task AddTaskAsync(long homeworkId, HomeworkTask task) + public async Task AddTaskAsync(long homeworkId, PostTaskViewModel taskViewModel) { + var task = taskViewModel.ToHomeworkTask(); task.HomeworkId = homeworkId; var homework = await _homeworksRepository.GetAsync(task.HomeworkId); @@ -56,7 +59,7 @@ public async Task AddTaskAsync(long homeworkId, HomeworkTask task) _eventBus.Publish(new NewHomeworkTaskEvent(task.Title, taskId, deadlineDate, course.Name, course.Id, studentIds)); - return taskId; + return await GetTaskAsync(taskId, true); } public async Task DeleteTaskAsync(long taskId) @@ -64,8 +67,10 @@ public async Task DeleteTaskAsync(long taskId) await _tasksRepository.DeleteAsync(taskId); } - public async Task UpdateTaskAsync(long taskId, HomeworkTask update, ActionOptions options) + public async Task UpdateTaskAsync(long taskId, PostTaskViewModel taskViewModel, + ActionOptions options) { + var update = taskViewModel.ToHomeworkTask(); var task = await _tasksRepository.GetWithHomeworkAsync(taskId); if (task == null) throw new InvalidOperationException("Task not found"); @@ -85,13 +90,10 @@ public async Task UpdateTaskAsync(long taskId, HomeworkTask update DeadlineDate = update.DeadlineDate, HasDeadline = update.HasDeadline, IsDeadlineStrict = update.IsDeadlineStrict, - PublicationDate = update.PublicationDate - }); + PublicationDate = update.PublicationDate, + }, update.Criteria); - var updatedTask = await _tasksRepository.GetAsync(taskId); - updatedTask.Homework = task.Homework; - CourseDomain.FillTask(updatedTask.Homework, updatedTask); - return updatedTask; + return await GetTaskAsync(taskId, true); } } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Startup.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Startup.cs index c1a6b9957..ae4454029 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Startup.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Startup.cs @@ -1,9 +1,11 @@ using HwProj.AuthService.Client; +using HwProj.ContentService.Client; using HwProj.CoursesService.API.Filters; using HwProj.CoursesService.API.Models; using HwProj.CoursesService.API.Repositories; using HwProj.CoursesService.API.Repositories.Groups; using HwProj.CoursesService.API.Services; +using HwProj.EventBus.Client; using HwProj.Utils.Configuration; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -39,6 +41,7 @@ public void ConfigureServices(IServiceCollection services) services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); @@ -46,6 +49,7 @@ public void ConfigureServices(IServiceCollection services) services.AddHttpClient(); services.AddAuthServiceClient(); + services.AddContentServiceClient(); services.ConfigureHwProjServices("Courses API"); } diff --git a/HwProj.CoursesService/HwProj.CoursesService.Client/CoursesServiceClient.cs b/HwProj.CoursesService/HwProj.CoursesService.Client/CoursesServiceClient.cs index cf82917cd..2cbd55fd2 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.Client/CoursesServiceClient.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.Client/CoursesServiceClient.cs @@ -6,8 +6,6 @@ using System.Threading.Tasks; using HwProj.Exceptions; using HwProj.HttpUtils; -using HwProj.Models.AuthService.DTO; -using HwProj.Models.CoursesService; using HwProj.Models.CoursesService.DTO; using HwProj.Models.CoursesService.ViewModels; using HwProj.Models.Result; @@ -41,6 +39,17 @@ public async Task GetAllCourses() return await response.DeserializeAsync(); } + public async Task GetCourseView(long courseId) + { + using var httpRequest = new HttpRequestMessage( + HttpMethod.Get, + _coursesServiceUri + $"api/Courses/view/{courseId}"); + + httpRequest.TryAddUserId(_httpContextAccessor); + var response = await _httpClient.SendAsync(httpRequest); + return response.IsSuccessStatusCode ? await response.DeserializeAsync() : null; + } + public async Task GetCourseByTask(long taskId) { using var httpRequest = new HttpRequestMessage( @@ -80,7 +89,7 @@ public async Task> GetCourseByIdForMentor(long courseId, strin }; } - public async Task> GetAllCourseData(long courseId) + public async Task> GetCourseDataRaw(long courseId) { using var httpRequest = new HttpRequestMessage( HttpMethod.Get, @@ -220,7 +229,7 @@ public async Task GetTaskDeadlines() return await response.DeserializeAsync(); } - public async Task> AddHomeworkToCourse(CreateHomeworkViewModel model, long courseId) + public async Task> AddHomeworkToCourse(CreateHomeworkViewModel model, long courseId) { using var httpRequest = new HttpRequestMessage( HttpMethod.Post, @@ -238,10 +247,12 @@ public async Task> AddHomeworkToCourse(CreateHomeworkViewModel mode var response = await _httpClient.SendAsync(httpRequest); return response.StatusCode switch { - HttpStatusCode.Forbidden => Result.Failed(), - HttpStatusCode.OK => Result.Success(await response.DeserializeAsync()), - HttpStatusCode.BadRequest => Result.Failed(await response.DeserializeAsync()), - _ => Result.Failed(), + HttpStatusCode.Forbidden => Result.Failed(), + HttpStatusCode.OK => Result.Success( + await response.DeserializeAsync()), + HttpStatusCode.BadRequest => Result.Failed( + await response.DeserializeAsync()), + _ => Result.Failed(), }; } @@ -305,11 +316,11 @@ public async Task DeleteHomework(long homeworkId) return response.IsSuccessStatusCode ? Result.Success() : Result.Failed(response.ReasonPhrase); } - public async Task GetTask(long taskId) + public async Task GetTask(long taskId, bool withCriteria = false) { using var httpRequest = new HttpRequestMessage( HttpMethod.Get, - _coursesServiceUri + $"api/Tasks/get/{taskId}"); + _coursesServiceUri + $"api/Tasks/get/{taskId}?withCriteria={withCriteria}"); httpRequest.TryAddUserId(_httpContextAccessor); @@ -329,7 +340,7 @@ public async Task GetForEditingTask(long taskId return await response.DeserializeAsync(); } - public async Task> AddTask(long homeworkId, CreateTaskViewModel taskViewModel) + public async Task> AddTask(long homeworkId, PostTaskViewModel taskViewModel) { using var httpRequest = new HttpRequestMessage( HttpMethod.Post, @@ -346,10 +357,12 @@ public async Task> AddTask(long homeworkId, CreateTaskViewModel tas var response = await _httpClient.SendAsync(httpRequest); return response.StatusCode switch { - HttpStatusCode.Forbidden => Result.Failed(), - HttpStatusCode.OK => Result.Success(await response.DeserializeAsync()), - HttpStatusCode.BadRequest => Result.Failed(await response.DeserializeAsync()), - _ => Result.Failed(), + HttpStatusCode.Forbidden => Result.Failed(), + HttpStatusCode.OK => Result.Success( + await response.DeserializeAsync()), + HttpStatusCode.BadRequest => Result.Failed( + await response.DeserializeAsync()), + _ => Result.Failed(), }; } @@ -364,7 +377,7 @@ public async Task DeleteTask(long taskId) return response.IsSuccessStatusCode ? Result.Success() : Result.Failed(response.ReasonPhrase); } - public async Task> UpdateTask(long taskId, CreateTaskViewModel taskViewModel) + public async Task> UpdateTask(long taskId, PostTaskViewModel taskViewModel) { using var httpRequest = new HttpRequestMessage( HttpMethod.Put, @@ -521,20 +534,6 @@ public async Task AcceptLecturer(long courseId, string lecturerEmail, st : Result.Failed(response.ReasonPhrase); } - public async Task> GetLecturersAvailableForCourse(long courseId) - { - using var httpRequest = new HttpRequestMessage( - HttpMethod.Get, - _coursesServiceUri + $"api/Courses/getLecturersAvailableForCourse/{courseId}"); - - httpRequest.TryAddUserId(_httpContextAccessor); - - var response = await _httpClient.SendAsync(httpRequest); - return response.IsSuccessStatusCode - ? Result.Success(await response.DeserializeAsync()) - : Result.Failed(response.ReasonPhrase); - } - public async Task GetCourseLecturersIds(long courseId) { using var httpRequest = new HttpRequestMessage( @@ -605,6 +604,17 @@ public async Task GetQuestionsForTask(long taskId) return await response.DeserializeAsync(); } + public async Task GetOpenQuestions() + { + using var httpRequest = new HttpRequestMessage( + HttpMethod.Get, + _coursesServiceUri + "api/Tasks/openQuestions"); + + httpRequest.TryAddUserId(_httpContextAccessor); + var response = await _httpClient.SendAsync(httpRequest); + return await response.DeserializeAsync(); + } + public async Task AddAnswerForQuestion(AddAnswerForQuestionDto answer) { using var httpRequest = new HttpRequestMessage( diff --git a/HwProj.CoursesService/HwProj.CoursesService.Client/ICoursesServiceClient.cs b/HwProj.CoursesService/HwProj.CoursesService.Client/ICoursesServiceClient.cs index 578630b6b..da84eb73b 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.Client/ICoursesServiceClient.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.Client/ICoursesServiceClient.cs @@ -1,5 +1,4 @@ using System.Threading.Tasks; -using HwProj.Models.AuthService.DTO; using HwProj.Models.CoursesService.DTO; using HwProj.Models.CoursesService.ViewModels; using HwProj.Models.Result; @@ -9,9 +8,11 @@ namespace HwProj.CoursesService.Client public interface ICoursesServiceClient { Task GetAllCourses(); + Task GetCourseView(long courseId); Task GetCourseById(long courseId); Task> GetCourseByIdForMentor(long courseId, string mentorId); - Task> GetAllCourseData(long courseId); + /// Получить полную информацию о курсе без учетов фильтров для преподавателей + Task> GetCourseDataRaw(long courseId); Task GetCourseByTask(long taskId); Task DeleteCourse(long courseId); Task> CreateCourse(CreateCourseViewModel model); @@ -25,16 +26,16 @@ Task UpdateStudentCharacteristics(long courseId, string studentId, Task GetAllUserCourses(); Task GetTaskDeadlines(); - Task> AddHomeworkToCourse(CreateHomeworkViewModel model, long courseId); + Task> AddHomeworkToCourse(CreateHomeworkViewModel model, long courseId); Task GetHomework(long homeworkId); Task GetForEditingHomework(long homeworkId); Task> UpdateHomework(long homeworkId, CreateHomeworkViewModel model); Task DeleteHomework(long homeworkId); - Task GetTask(long taskId); + Task GetTask(long taskId, bool withCriteria = false); Task GetForEditingTask(long taskId); - Task> AddTask(long homeworkId, CreateTaskViewModel taskViewModel); + Task> AddTask(long homeworkId, PostTaskViewModel taskViewModel); Task DeleteTask(long taskId); - Task> UpdateTask(long taskId, CreateTaskViewModel taskViewModel); + Task> UpdateTask(long taskId, PostTaskViewModel taskViewModel); Task GetAllCourseGroups(long courseId); Task CreateCourseGroup(CreateGroupViewModel model, long courseId); Task DeleteCourseGroup(long courseId, long groupId); @@ -45,13 +46,13 @@ Task UpdateStudentCharacteristics(long courseId, string studentId, Task GetGroupsById(params long[] groupIds); Task GetGroupTasks(long groupId); Task AcceptLecturer(long courseId, string lecturerEmail, string lecturerId); - Task> GetLecturersAvailableForCourse(long courseId); Task GetCourseLecturersIds(long courseId); Task> GetAllTagsForCourse(long courseId); Task> CreateOrUpdateCourseFilter(long courseId, CreateCourseFilterDTO model); Task AddQuestionForTask(AddTaskQuestionDto question); Task GetQuestionsForTask(long taskId); Task AddAnswerForQuestion(AddAnswerForQuestionDto answer); + Task GetOpenQuestions(); Task GetMentorsToAssignedStudents(long courseId); Task Ping(); } diff --git a/HwProj.CoursesService/HwProj.CoursesService.Tests/CoursesServiceTests.cs b/HwProj.CoursesService/HwProj.CoursesService.Tests/CoursesServiceTests.cs index f26eecac3..7bc48943d 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.Tests/CoursesServiceTests.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.Tests/CoursesServiceTests.cs @@ -56,33 +56,33 @@ private static CreateCourseViewModel GenerateCreateCourseViewModel() } private static CreateHomeworkViewModel GenerateCreateHomeworkViewModel(DateTime publicationDate, - bool hasDeadline, DateTime? deadlineDate, bool isStrict, List? tasks = null) + bool hasDeadline, DateTime? deadlineDate, bool isStrict, List? tasks = null) => new Fixture().Build() .With(hvc => hvc.HasDeadline, hasDeadline) .With(hvc => hvc.PublicationDate, publicationDate) .With(hvc => hvc.DeadlineDate, deadlineDate) .With(hvc => hvc.IsDeadlineStrict, isStrict) - .With(hvm => hvm.Tasks, tasks ?? new List()) + .With(hvm => hvm.Tasks, tasks ?? new List()) .Create(); private static CreateHomeworkViewModel GenerateDefaultHomeworkViewModel() => GenerateCreateHomeworkViewModel(utcNow, false, null, false); - private static CreateTaskViewModel GenerateCreateTaskViewModel(DateTime? publicationDate, + private static PostTaskViewModel GenerateCreateTaskViewModel(DateTime? publicationDate, bool? hasDeadline, DateTime? deadlineDate, bool? isStrict) - => new Fixture().Build() + => new Fixture().Build() .With(hvc => hvc.HasDeadline, hasDeadline) .With(hvc => hvc.PublicationDate, publicationDate) .With(hvc => hvc.DeadlineDate, deadlineDate) .With(hvc => hvc.IsDeadlineStrict, isStrict) .Create(); - private static CreateTaskViewModel GenerateDefaultTaskViewModel() + private static PostTaskViewModel GenerateDefaultTaskViewModel() => GenerateCreateTaskViewModel(null, null, null, null); - private static CreateTaskViewModel GenerateCreateTaskViewModelWithNullProperties() + private static PostTaskViewModel GenerateCreateTaskViewModelWithNullProperties() { - return new Fixture().Build() + return new Fixture().Build() .Without(t => t.PublicationDate) .Without(t => t.DeadlineDate) .Without(t => t.IsDeadlineStrict) @@ -135,7 +135,7 @@ private static async Task CreateCourse(CoursesServiceClient courseClient, return (id, lectureCourseClient); } - private async Task<(long courseId, CreateHomeworkViewModel homework, Result homeworkResult, CoursesServiceClient client)> CreateCourseWithHomework() + private async Task<(long courseId, CreateHomeworkViewModel homework, Result homeworkResult, CoursesServiceClient client)> CreateCourseWithHomework() { var course = await CreateClientAndCourse(); var homework = GenerateDefaultHomeworkViewModel(); @@ -145,13 +145,13 @@ private static async Task CreateCourse(CoursesServiceClient courseClient, } private async Task<(Result editResult, HomeworkTaskForEditingViewModel tasksFromDb)> - AddTaskToHomeworkAndUpdate(CreateTaskViewModel firstTaskState, CreateTaskViewModel secondTaskState) + AddTaskToHomeworkAndUpdate(PostTaskViewModel firstTaskState, PostTaskViewModel secondTaskState) { var homework = GenerateDefaultHomeworkViewModel(); var homeworkResult = await client.AddHomeworkToCourse(homework, courseId); - var taskResult = await client.AddTask(homeworkResult.Value, firstTaskState); - var editResult = await client.UpdateTask(taskResult.Value, secondTaskState); - var taskFromDb = await client.GetForEditingTask(taskResult.Value); + var taskResult = await client.AddTask(homeworkResult.Value.Id, firstTaskState); + var editResult = await client.UpdateTask(taskResult.Value.Id, secondTaskState); + var taskFromDb = await client.GetForEditingTask(taskResult.Value.Id); return (editResult, taskFromDb); } @@ -174,12 +174,12 @@ public async Task NullTaskPropertiesAfterShouldBeInheritedFromHomework() .With(hvc => hvc.PublicationDate, expectedPublicationDate) .With(hvc => hvc.DeadlineDate, expectedDeadlineDate) .With(hvc => hvc.IsDeadlineStrict, expectedIsDeadlineStrict) - .With(hvc => hvc.Tasks, new List { GenerateCreateTaskViewModelWithNullProperties() }) + .With(hvc => hvc.Tasks, new List { GenerateCreateTaskViewModelWithNullProperties() }) .Create(); var homeworkResult = await client.AddHomeworkToCourse(homework, courseId); - var actualResult = (await client.GetHomework(homeworkResult.Value)).Tasks.FirstOrDefault(); + var actualResult = (await client.GetHomework(homeworkResult.Value.Id)).Tasks.FirstOrDefault(); homeworkResult.Succeeded.Should().BeTrue(); homeworkResult.Errors.Should().BeNull(); @@ -192,7 +192,7 @@ public async Task NullTaskPropertiesAfterShouldBeInheritedFromHomework() } [TestCaseSource(nameof(InvalidCreateHomeworkData))] - public async Task AddHomeworkWithInvalidPropertiesShouldReturnFailedResult((DateTime publication, bool hasDeadline, DateTime? deadline, bool isStrict, List tasks) data) + public async Task AddHomeworkWithInvalidPropertiesShouldReturnFailedResult((DateTime publication, bool hasDeadline, DateTime? deadline, bool isStrict, List tasks) data) { var homework = GenerateCreateHomeworkViewModel(data.publication, data.hasDeadline, data.deadline, data.isStrict, data.tasks); @@ -206,7 +206,7 @@ public async Task AddHomeworkWithInvalidPropertiesShouldReturnFailedResult((Date } [TestCaseSource(nameof(ValidCreateHomeworkData))] - public async Task AddHomeworkWithValidPropertiesShouldReturnSucceededResult((DateTime publication, bool hasDeadline, DateTime? deadline, bool isStrict, List? tasks) data) + public async Task AddHomeworkWithValidPropertiesShouldReturnSucceededResult((DateTime publication, bool hasDeadline, DateTime? deadline, bool isStrict, List? tasks) data) { var homework = GenerateCreateHomeworkViewModel(data.publication, data.hasDeadline, data.deadline, data.isStrict, data.tasks); var homeworkResult = await client.AddHomeworkToCourse(homework, courseId); @@ -217,14 +217,14 @@ public async Task AddHomeworkWithValidPropertiesShouldReturnSucceededResult((Dat course?.Homeworks.Should().ContainEquivalentOf(homework, option => option.ExcludingMissingMembers().Excluding(h => h.Tasks)); } - + [TestCaseSource(nameof(InvalidCreateTaskData))] public async Task AddTaskWithInvalidPropertiesShouldReturnFailedResult((CreateHomeworkViewModel homework, DateTime? publication, bool? hasDeadline, DateTime? deadline, bool? isStrict) data) { var task = GenerateCreateTaskViewModel(data.publication, data.hasDeadline, data.deadline, data.isStrict); var homeworkResult = await client.AddHomeworkToCourse(data.homework, courseId); - var taskResult = await client.AddTask(homeworkResult.Value, task); - var homeworkFromDb = await client.GetForEditingHomework(homeworkResult.Value); + var taskResult = await client.AddTask(homeworkResult.Value.Id, task); + var homeworkFromDb = await client.GetForEditingHomework(homeworkResult.Value.Id); homeworkResult.Succeeded.Should().BeTrue(); @@ -241,8 +241,8 @@ public async Task AddTaskWithValidPropertiesShouldReturnSucceededResult( { var task = GenerateCreateTaskViewModel(data.publication, data.hasDeadline, data.deadline, data.isStrict); var homeworkResult = await client.AddHomeworkToCourse(data.homework, courseId); - var taskResult = await client.AddTask(homeworkResult.Value, task); - var homeworkFromDb = await client.GetForEditingHomework(homeworkResult.Value); + var taskResult = await client.AddTask(homeworkResult.Value.Id, task); + var homeworkFromDb = await client.GetForEditingHomework(homeworkResult.Value.Id); homeworkResult.Succeeded.Should().BeTrue(); @@ -261,8 +261,8 @@ public async Task UpdateHomeworkWithInvalidPropertiesShouldReturnFailedResult( var secondHomeworkState = GenerateCreateHomeworkViewModel(data.publication, data.hasDeadline, data.deadline, data.isStrict); var homeworkResult = await client.AddHomeworkToCourse(data.firstHomeworkState, courseId); - var updateResult = await client.UpdateHomework(homeworkResult.Value, secondHomeworkState); - var homeworkFromDb = await client.GetHomework(homeworkResult.Value); + var updateResult = await client.UpdateHomework(homeworkResult.Value.Id, secondHomeworkState); + var homeworkFromDb = await client.GetHomework(homeworkResult.Value.Id); homeworkFromDb.Should().NotBeNull(); homeworkResult.Succeeded.Should().BeTrue(); @@ -281,8 +281,8 @@ public async Task UpdateHomeworkWithValidPropertiesShouldReturnSucceededResult( var secondHomeworkState = GenerateCreateHomeworkViewModel(data.publication, data.hasDeadline, data.deadline, data.isStrict); var homeworkResult = await client.AddHomeworkToCourse(data.firstHomeworkState, courseId); - var updateResult = await client.UpdateHomework(homeworkResult.Value, secondHomeworkState); - var taskFromDb = await client.GetHomework(homeworkResult.Value); + var updateResult = await client.UpdateHomework(homeworkResult.Value.Id, secondHomeworkState); + var taskFromDb = await client.GetHomework(homeworkResult.Value.Id); taskFromDb.Should().NotBeNull(); homeworkResult.Succeeded.Should().BeTrue(); @@ -341,8 +341,8 @@ public async Task AddTaskByMentorNotFromThisCourseShouldReturnFailedResult() var (_, _, homeworkResult, _) = await CreateCourseWithHomework(); var task = GenerateDefaultTaskViewModel(); - var addHomeworkResult = await client.AddTask(homeworkResult.Value, task); - var homeworkFromDb = await client.GetHomework(homeworkResult.Value); + var addHomeworkResult = await client.AddTask(homeworkResult.Value.Id, task); + var homeworkFromDb = await client.GetHomework(homeworkResult.Value.Id); addHomeworkResult.Succeeded.Should().BeFalse(); homeworkFromDb.Tasks.Should().BeEmpty(); @@ -354,8 +354,8 @@ public async Task UpdateHomeworkByMentorNotFromThisCourseShouldReturnFailedResul var (_, createdHomework, homeworkResult, _) = await CreateCourseWithHomework(); var homework = GenerateCreateHomeworkViewModel(utcNow.AddHours(2), true, utcNow.AddHours(4), true); - var updateHomeworkResult = await client.UpdateHomework(homeworkResult.Value, homework); - var homeworkFromDb = await client.GetHomework(homeworkResult.Value); + var updateHomeworkResult = await client.UpdateHomework(homeworkResult.Value.Id, homework); + var homeworkFromDb = await client.GetHomework(homeworkResult.Value.Id); updateHomeworkResult.Succeeded.Should().BeFalse(); homeworkFromDb.Should().BeEquivalentTo(createdHomework, @@ -369,9 +369,9 @@ public async Task UpdateTaskByMentorNotFromThisCourseShouldReturnFailedResult() var oldTask = GenerateDefaultTaskViewModel(); var newTask = GenerateCreateTaskViewModel(utcNow, false, null, false); - var addTaskResult = await foreignClient.AddTask(homeworkResult.Value, oldTask); - var updateTaskResult = await client.UpdateTask(addTaskResult.Value, newTask); - var taskFromDb = await foreignClient.GetForEditingTask(addTaskResult.Value); + var addTaskResult = await foreignClient.AddTask(homeworkResult.Value.Id, oldTask); + var updateTaskResult = await client.UpdateTask(addTaskResult.Value.Id, newTask); + var taskFromDb = await foreignClient.GetForEditingTask(addTaskResult.Value.Id); updateTaskResult.Succeeded.Should().BeFalse(); taskFromDb.Should().BeEquivalentTo(oldTask, @@ -380,32 +380,32 @@ public async Task UpdateTaskByMentorNotFromThisCourseShouldReturnFailedResult() // TODO: тесты для GetForEditingTask/Homework - public static IEnumerable<(DateTime publication, bool hasDeadline, DateTime? deadline, bool isStrict, List? tasks)> ValidCreateHomeworkData() + public static IEnumerable<(DateTime publication, bool hasDeadline, DateTime? deadline, bool isStrict, List? tasks)> ValidCreateHomeworkData() { yield return (utcNow.AddHours(1), true, utcNow.AddHours(2), true, null); yield return (utcNow, false, null, false, null); yield return (utcNow, false, null, false, - new List {GenerateCreateTaskViewModel(utcNow.AddHours(1), null, null, null)}); + new List {GenerateCreateTaskViewModel(utcNow.AddHours(1), null, null, null)}); yield return (utcNow, false, null, false, - new List {GenerateCreateTaskViewModel(null, null, null, null)}); + new List {GenerateCreateTaskViewModel(null, null, null, null)}); yield return (utcNow, false, null, false, - new List {GenerateCreateTaskViewModel(utcNow, true, utcNow, false)}); + new List {GenerateCreateTaskViewModel(utcNow, true, utcNow, false)}); yield return (utcNow, false, null, false, - new List {GenerateCreateTaskViewModel(utcNow, null, null, false)}); + new List {GenerateCreateTaskViewModel(utcNow, null, null, false)}); } - public static IEnumerable<(DateTime publication, bool hasDeadline, DateTime? deadline, bool isStrict, List? tasks)> InvalidCreateHomeworkData() + public static IEnumerable<(DateTime publication, bool hasDeadline, DateTime? deadline, bool isStrict, List? tasks)> InvalidCreateHomeworkData() { yield return (utcNow, false, utcNow, false, null); yield return (utcNow.AddHours(1), false, utcNow, false, null); yield return (utcNow, true, null, false, null); yield return (utcNow, false, null, true, null); yield return (utcNow, false, null, false, - new List {GenerateCreateTaskViewModel(utcNow.AddHours(-1), null, null, null)}); + new List {GenerateCreateTaskViewModel(utcNow.AddHours(-1), null, null, null)}); yield return (utcNow, false, null, false, - new List {GenerateCreateTaskViewModel(utcNow, true, null, true)}); + new List {GenerateCreateTaskViewModel(utcNow, true, null, true)}); yield return (utcNow, false, null, false, - new List {GenerateCreateTaskViewModel(utcNow, null, null, true)}); + new List {GenerateCreateTaskViewModel(utcNow, null, null, true)}); } public static IEnumerable<(CreateHomeworkViewModel, DateTime? publication, bool? hasDeadline, DateTime? deadline, bool? isStrict)> InvalidCreateTaskData() @@ -439,7 +439,7 @@ public async Task UpdateTaskByMentorNotFromThisCourseShouldReturnFailedResult() { var publishedHomework = GenerateCreateHomeworkViewModel(utcNow.AddHours(-1), false, null, false); var delayedHomework = GenerateCreateHomeworkViewModel(utcNow.AddHours(1), false, null, false, - new List { GenerateCreateTaskViewModel(utcNow.AddHours(1), null, null, null)}); + new List { GenerateCreateTaskViewModel(utcNow.AddHours(1), null, null, null)}); yield return (publishedHomework, publishedHomework.PublicationDate.AddHours(1), true, utcNow, true); yield return (delayedHomework, delayedHomework.Tasks[0].PublicationDate?.AddHours(1) ?? utcNow, true, @@ -450,7 +450,7 @@ public async Task UpdateTaskByMentorNotFromThisCourseShouldReturnFailedResult() { var publishedHomework = GenerateCreateHomeworkViewModel(utcNow.AddHours(-1), false, null, false); var delayedHomework = GenerateCreateHomeworkViewModel(utcNow.AddHours(1), false, null, false, - new List { GenerateCreateTaskViewModel(utcNow.AddHours(1), null, null, null)}); + new List { GenerateCreateTaskViewModel(utcNow.AddHours(1), null, null, null)}); yield return (publishedHomework, publishedHomework.PublicationDate, true, publishedHomework.PublicationDate, true); yield return (delayedHomework, delayedHomework.PublicationDate, true, utcNow.AddHours(10), true); diff --git a/HwProj.EventBus/HwProj.EventBus.Client/ConfigurationExtensions.cs b/HwProj.EventBus/HwProj.EventBus.Client/ConfigurationExtensions.cs new file mode 100644 index 000000000..38896bee2 --- /dev/null +++ b/HwProj.EventBus/HwProj.EventBus.Client/ConfigurationExtensions.cs @@ -0,0 +1,59 @@ +using System; +using System.Linq; +using System.Net.Sockets; +using HwProj.EventBus.Client.Implementations; +using HwProj.EventBus.Client.Interfaces; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Polly; +using RabbitMQ.Client; +using RabbitMQ.Client.Exceptions; + +namespace HwProj.EventBus.Client +{ + public static class ConfigurationExtensions + { + public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration) + { + var eventBusSection = configuration.GetSection("EventBus"); + + var retryCount = 5; + if (!string.IsNullOrEmpty(eventBusSection["EventBusRetryCount"])) + { + retryCount = int.Parse(eventBusSection["EventBusRetryCount"]); + } + + services.AddSingleton(sp => Policy.Handle() + .Or() + .WaitAndRetry(retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))); + + services.AddSingleton(sp => new ConnectionFactory + { + HostName = eventBusSection["EventBusHostName"], + UserName = eventBusSection["EventBusUserName"], + Password = eventBusSection["EventBusPassword"], + VirtualHost = eventBusSection["EventBusVirtualHost"] + }); + + services.AddSingleton(); + services.AddSingleton(); + + var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes()).ToList(); + var eventTypes = types.Where(x => typeof(Event).IsAssignableFrom(x)); + foreach (var eventType in eventTypes) + { + var fullTypeInterface = typeof(IEventHandler<>).MakeGenericType(eventType); + var handlersTypes = types.Where(x => + fullTypeInterface.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract); + + foreach (var handlerType in handlersTypes) + { + services.AddTransient(handlerType); + } + } + + return services; + } + + } +} diff --git a/HwProj.EventBus/HwProj.EventBus.Client/HwProj.EventBus.Client.csproj b/HwProj.EventBus/HwProj.EventBus.Client/HwProj.EventBus.Client.csproj index 7932fcc9d..d6b2fc1f2 100644 --- a/HwProj.EventBus/HwProj.EventBus.Client/HwProj.EventBus.Client.csproj +++ b/HwProj.EventBus/HwProj.EventBus.Client/HwProj.EventBus.Client.csproj @@ -2,7 +2,7 @@ Library - netcoreapp2.2 + netstandard2.0 HwProj.EventBus.Client @@ -13,7 +13,7 @@ - + diff --git a/HwProj.EventBus/HwProj.EventBus.Client/Implementations/EventBusRabbitMQ.cs b/HwProj.EventBus/HwProj.EventBus.Client/Implementations/EventBusRabbitMQ.cs index 2ef286191..0bc71ec56 100644 --- a/HwProj.EventBus/HwProj.EventBus.Client/Implementations/EventBusRabbitMQ.cs +++ b/HwProj.EventBus/HwProj.EventBus.Client/Implementations/EventBusRabbitMQ.cs @@ -1,10 +1,9 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading.Tasks; using HwProj.EventBus.Client.Interfaces; -using Microsoft.AspNetCore.DataProtection; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using Polly.Retry; @@ -30,12 +29,11 @@ public class EventBusRabbitMq : IEventBus, IDisposable private readonly Dictionary> _handlers = new Dictionary>(); - public EventBusRabbitMq(IDefaultConnection connection, IServiceProvider serviceProvider, - IServiceScopeFactory scopeFactory, RetryPolicy policy) + public EventBusRabbitMq(IDefaultConnection connection, IConfiguration configuration, IConnectionFactory connectionFactory, IServiceScopeFactory scopeFactory, RetryPolicy policy) { _connection = connection; _scopeFactory = scopeFactory; - _queueName = serviceProvider.GetApplicationUniqueIdentifier().Split('\\').Last(); + _queueName = configuration.GetSection("EventBus")["EventBusQueueName"]; _policy = policy; _consumerChannel = CreateConsumerChannel(); } diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/AdminRegisterEvent.cs b/HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/AdminRegisterEvent.cs new file mode 100644 index 000000000..c3e5762a8 --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/AdminRegisterEvent.cs @@ -0,0 +1,11 @@ +namespace HwProj.NotificationService.Events.AuthService +{ + public class AdminRegisterEvent : RegisterEvent + { + public AdminRegisterEvent(string userId, string email, string name, string surname = "", string middleName = "") + : base(userId, email, name, surname, middleName) + { + + } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/InviteLecturerEvent.cs b/HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/InviteLecturerEvent.cs new file mode 100644 index 000000000..81b3ff76d --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/InviteLecturerEvent.cs @@ -0,0 +1,10 @@ +using HwProj.EventBus.Client; + +namespace HwProj.NotificationService.Events.AuthService +{ + public class InviteLecturerEvent : Event + { + public string UserId { get; set; } + public string UserEmail { get; set; } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/PasswordRecoveryEvent.cs b/HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/PasswordRecoveryEvent.cs new file mode 100644 index 000000000..4e48570f7 --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/PasswordRecoveryEvent.cs @@ -0,0 +1,13 @@ +using HwProj.EventBus.Client; + +namespace HwProj.NotificationService.Events.AuthService +{ + public class PasswordRecoveryEvent : Event + { + public string UserId { get; set; } + public string Name { get; set; } + public string Surname { get; set; } + public string Email { get; set; } + public string Token { get; set; } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/RegisterEvent.cs b/HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/RegisterEvent.cs new file mode 100644 index 000000000..3f6d4f864 --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/RegisterEvent.cs @@ -0,0 +1,22 @@ +using HwProj.EventBus.Client; + +namespace HwProj.NotificationService.Events.AuthService +{ + public abstract class RegisterEvent : Event + { + public string UserId { get; set; } + public string Name { get; set; } + public string Surname { get; set; } + public string MiddleName { get; set; } + public string Email { get; set; } + + protected RegisterEvent(string userId, string email, string name, string surname = "", string middleName = "") + { + UserId = userId; + Name = name; + Surname = surname; + MiddleName = middleName; + Email = email; + } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/StudentRegisterEvent.cs b/HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/StudentRegisterEvent.cs new file mode 100644 index 000000000..bc5b8ccd8 --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/AuthService/StudentRegisterEvent.cs @@ -0,0 +1,11 @@ +namespace HwProj.NotificationService.Events.AuthService +{ + public class StudentRegisterEvent : RegisterEvent + { + public StudentRegisterEvent(string userId, string email, string name, string surname = "", string middleName = "") + : base(userId, email, name, surname, middleName) + { + } + public string ChangePasswordToken { get; set; } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/LecturerAcceptToCourseEvent.cs b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/LecturerAcceptToCourseEvent.cs new file mode 100644 index 000000000..c4970513d --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/LecturerAcceptToCourseEvent.cs @@ -0,0 +1,12 @@ +using HwProj.EventBus.Client; + +namespace HwProj.NotificationService.Events.CoursesService +{ + public class LecturerAcceptToCourseEvent : Event + { + public long CourseId { get; set; } + public string CourseName { get; set; } + public string MentorIds { get; set; } + public string StudentId { get; set; } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/LecturerInvitedToCourseEvent.cs b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/LecturerInvitedToCourseEvent.cs new file mode 100644 index 000000000..81ace110d --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/LecturerInvitedToCourseEvent.cs @@ -0,0 +1,12 @@ +using HwProj.EventBus.Client; + +namespace HwProj.NotificationService.Events.CoursesService +{ + public class LecturerInvitedToCourseEvent : Event + { + public long CourseId { get; set; } + public string CourseName { get; set; } + public string MentorId { get; set; } + public string MentorEmail { get; set; } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/LecturerRejectToCourseEvent.cs b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/LecturerRejectToCourseEvent.cs new file mode 100644 index 000000000..65e6d05fd --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/LecturerRejectToCourseEvent.cs @@ -0,0 +1,12 @@ +using HwProj.EventBus.Client; + +namespace HwProj.NotificationService.Events.CoursesService +{ + public class LecturerRejectToCourseEvent : Event + { + public long CourseId { get; set; } + public string CourseName { get; set; } + public string MentorIds { get; set; } + public string StudentId { get; set; } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/NewCourseMateEvent.cs b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/NewCourseMateEvent.cs new file mode 100644 index 000000000..c96eef9c2 --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/NewCourseMateEvent.cs @@ -0,0 +1,13 @@ +using HwProj.EventBus.Client; + +namespace HwProj.NotificationService.Events.CoursesService +{ + public class NewCourseMateEvent : Event + { + public long CourseId { get; set; } + public string CourseName { get; set; } + public string MentorIds { get; set; } + public string StudentId { get; set; } + public bool IsAccepted { get; set; } + } +} \ No newline at end of file diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/NewHomeworkEvent.cs b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/NewHomeworkEvent.cs new file mode 100644 index 000000000..0384087cc --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/NewHomeworkEvent.cs @@ -0,0 +1,23 @@ +using System; +using HwProj.EventBus.Client; + +namespace HwProj.NotificationService.Events.CoursesService +{ + public class NewHomeworkEvent : Event + { + public NewHomeworkEvent(string homeworkTitle, string courseName, long courseId, string[] studentIds, DateTime? deadlineDate) + { + HomeworkTitle = homeworkTitle; + CourseName = courseName; + StudentIds = studentIds; + DeadlineDate = deadlineDate; + CourseId = courseId; + } + + public string HomeworkTitle { get; set; } + public string CourseName { get; set; } + public long CourseId { get; set; } + public DateTime? DeadlineDate { get; set; } + public string[] StudentIds { get; set; } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/NewHomeworkTaskEvent.cs b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/NewHomeworkTaskEvent.cs new file mode 100644 index 000000000..5ea6d0c9c --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/NewHomeworkTaskEvent.cs @@ -0,0 +1,25 @@ +using System; +using HwProj.EventBus.Client; + +namespace HwProj.NotificationService.Events.CoursesService +{ + public class NewHomeworkTaskEvent : Event + { + public NewHomeworkTaskEvent(string taskTitle, long taskId, DateTime? deadlineDate, string courseName, long courseId, string[] studentIds) + { + TaskTitle = taskTitle; + TaskId = taskId; + DeadlineDate = deadlineDate; + CourseName = courseName; + StudentIds = studentIds; + CourseId = courseId; + } + + public string TaskTitle { get; set; } + public long TaskId { get; set; } + public DateTime? DeadlineDate { get; set; } + public long CourseId { get; set; } + public string CourseName { get; set; } + public string[] StudentIds { get; set; } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/UpdateHomeworkEvent.cs b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/UpdateHomeworkEvent.cs new file mode 100644 index 000000000..283a4a97f --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/UpdateHomeworkEvent.cs @@ -0,0 +1,20 @@ +using HwProj.EventBus.Client; + +namespace HwProj.NotificationService.Events.CoursesService +{ + public class UpdateHomeworkEvent : Event + { + public UpdateHomeworkEvent(string homeworkTitle, long courseId, string courseName, string[] studentIds) + { + CourseId = courseId; + HomeworkTitle = homeworkTitle; + StudentIds = studentIds; + CourseName = courseName; + } + + public string HomeworkTitle { get; set; } + public string[] StudentIds { get; set; } + public long CourseId { get; set; } + public string CourseName { get; set; } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/UpdateSolutionMaxRatingEvent.cs b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/UpdateSolutionMaxRatingEvent.cs new file mode 100644 index 000000000..be5540200 --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/UpdateSolutionMaxRatingEvent.cs @@ -0,0 +1,18 @@ +using HwProj.EventBus.Client; + +namespace HwProj.NotificationService.Events.CoursesService +{ + public class UpdateSolutionMaxRatingEvent : Event + { + public long TaskId { get; set; } + public long SolutionId { get; set; } + public int MaxRating { get; set; } + + public UpdateSolutionMaxRatingEvent(long taskId, long solutionId, int rating) + { + TaskId = taskId; + MaxRating = rating; + SolutionId = solutionId; + } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/UpdateTaskMaxRatingEvent.cs b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/UpdateTaskMaxRatingEvent.cs new file mode 100644 index 000000000..1dc11db50 --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/CoursesService/UpdateTaskMaxRatingEvent.cs @@ -0,0 +1,22 @@ +using HwProj.EventBus.Client; + +namespace HwProj.NotificationService.Events.CoursesService +{ + public class UpdateTaskMaxRatingEvent : Event + { + public UpdateTaskMaxRatingEvent(string courseName, long courseId, string taskTitle, long taskId, string[] studentIds) + { + CourseName = courseName; + CourseId = courseId; + TaskTitle = taskTitle; + TaskId = taskId; + StudentIds = studentIds; + } + + public string CourseName { get; set; } + public long CourseId {get; set; } + public string TaskTitle { get; set; } + public long TaskId { get; set; } + public string[] StudentIds { get; set; } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/HwProj.NotificationService.Events.csproj b/HwProj.NotificationsService/HwProj.NotificationService.Events/HwProj.NotificationService.Events.csproj new file mode 100644 index 000000000..d6ac9c7a6 --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/HwProj.NotificationService.Events.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.0 + + + + + + + + diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/SolutionsService/RateEvent.cs b/HwProj.NotificationsService/HwProj.NotificationService.Events/SolutionsService/RateEvent.cs new file mode 100644 index 000000000..7070a418d --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/SolutionsService/RateEvent.cs @@ -0,0 +1,18 @@ +using HwProj.EventBus.Client; +using HwProj.Models.CoursesService.ViewModels; +using HwProj.Models.SolutionsService; + +namespace HwProj.NotificationService.Events.SolutionsService +{ + public class RateEvent : Event + { + public HomeworkTaskViewModel Task { get; set; } + public SolutionViewModel Solution { get; set; } + + public RateEvent(HomeworkTaskViewModel task, SolutionViewModel solution) + { + Task = task; + Solution = solution; + } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationService.Events/SolutionsService/StudentPassTaskEvent.cs b/HwProj.NotificationsService/HwProj.NotificationService.Events/SolutionsService/StudentPassTaskEvent.cs new file mode 100644 index 000000000..32e61b916 --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationService.Events/SolutionsService/StudentPassTaskEvent.cs @@ -0,0 +1,23 @@ +using HwProj.EventBus.Client; +using HwProj.Models.AuthService.DTO; +using HwProj.Models.CoursesService.ViewModels; +using HwProj.Models.SolutionsService; + +namespace HwProj.NotificationService.Events.SolutionsService +{ + public class StudentPassTaskEvent : Event + { + public CourseDTO Course { get; set; } + public SolutionViewModel Solution { get; set; } + public AccountDataDto Student { get; set; } + public HomeworkTaskViewModel Task { get; set; } + + public StudentPassTaskEvent(CourseDTO course, SolutionViewModel solution, AccountDataDto student, HomeworkTaskViewModel task) + { + Course = course; + Solution = solution; + Student= student; + Task = task; + } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/AutomapperProfile.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/AutomapperProfile.cs index 0395763ee..156acbbfd 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/AutomapperProfile.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/AutomapperProfile.cs @@ -1,5 +1,6 @@ using AutoMapper; using HwProj.Models.NotificationsService; +using HwProj.NotificationsService.API.Models; namespace HwProj.NotificationsService.API { diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Controllers/NotificationSettingsController.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Controllers/NotificationSettingsController.cs index 39191817b..adab446f8 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/Controllers/NotificationSettingsController.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/Controllers/NotificationSettingsController.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using HwProj.Models.NotificationsService; -using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; using Microsoft.AspNetCore.Mvc; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Dockerfile b/HwProj.NotificationsService/HwProj.NotificationsService.API/Dockerfile index 2733d4b86..72caa8fe9 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/Dockerfile +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/Dockerfile @@ -1,26 +1,28 @@ -FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY ["Directory.Build.props", "Directory.Build.props"] COPY ["HwProj.NotificationsService/HwProj.NotificationsService.API/", "HwProj.NotificationsService/HwProj.NotificationsService.API/"] -COPY ["HwProj.AuthService/HwProj.AuthService.API/", "HwProj.AuthService/HwProj.AuthService.API/"] -COPY ["HwProj.Common/HwProj.Utils/", "HwProj.Common/HwProj.Utils/"] +COPY ["HwProj.NotificationsService/HwProj.NotificationService.Events/", "HwProj.NotificationsService/HwProj.NotificationService.Events/"] +COPY ["HwProj.Common/HwProj.Common.Net8/", "HwProj.Common/HwProj.Common.Net8/"] COPY ["HwProj.EventBus/HwProj.EventBus.Client/", "HwProj.EventBus/HwProj.EventBus.Client/"] COPY ["HwProj.Common/HwProj.Models/", "HwProj.Common/HwProj.Models/"] COPY ["HwProj.Common/HwProj.Repositories/", "HwProj.Common/HwProj.Repositories/"] -COPY ["HwProj.SolutionsService/HwProj.SolutionsService.API/", "HwProj.SolutionsService/HwProj.SolutionsService.API/"] +COPY ["HwProj.Common/HwProj.Repositories.Net8/", "HwProj.Common/HwProj.Repositories.Net8/"] COPY ["HwProj.SolutionsService/HwProj.SolutionsService.Client/", "HwProj.SolutionsService/HwProj.SolutionsService.Client/"] COPY ["HwProj.Common/HwProj.Exceptions/", "HwProj.Common/HwProj.Exceptions/"] COPY ["HwProj.Common/HwProj.HttpUtils/", "HwProj.Common/HwProj.HttpUtils/"] COPY ["HwProj.CoursesService/HwProj.CoursesService.Client/", "HwProj.CoursesService/HwProj.CoursesService.Client/"] COPY ["HwProj.AuthService/HwProj.AuthService.Client/", "HwProj.AuthService/HwProj.AuthService.Client/"] + +COPY ["HwProj.ContentService/HwProj.ContentService.Client/", "HwProj.ContentService/HwProj.ContentService.Client/"] COPY ["HwProj.CoursesService/HwProj.CoursesService.API/", "HwProj.CoursesService/HwProj.CoursesService.API/"] WORKDIR "/src/HwProj.NotificationsService/HwProj.NotificationsService.API" RUN dotnet publish "HwProj.NotificationsService.API.csproj" -c Release -o /app/publish -FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim AS final +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final WORKDIR /app COPY --from=build /app/publish . diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/InviteLecturerEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/InviteLecturerEventHandler.cs index 1549cb68d..93eda1db6 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/InviteLecturerEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/InviteLecturerEventHandler.cs @@ -1,9 +1,7 @@ using System; using System.Threading.Tasks; -using HwProj.AuthService.API.Events; -using HwProj.AuthService.Client; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models.NotificationsService; +using HwProj.NotificationService.Events.AuthService; using HwProj.NotificationsService.API.Models; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; @@ -19,7 +17,6 @@ public class InviteLecturerEventHandler : EventHandlerBase public InviteLecturerEventHandler( INotificationsRepository notificationRepository, IEmailService emailService, - IAuthServiceClient authServiceClient, INotificationSettingsService settingsService) { _notificationRepository = notificationRepository; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerAcceptToCourseEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerAcceptToCourseEventHandler.cs index 6bf7ad74e..5dbe4875a 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerAcceptToCourseEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerAcceptToCourseEventHandler.cs @@ -1,9 +1,9 @@ using System; using System.Threading.Tasks; using HwProj.AuthService.Client; -using HwProj.CoursesService.API.Events; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models.NotificationsService; +using HwProj.NotificationService.Events.CoursesService; +using HwProj.NotificationsService.API.Models; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; using Microsoft.Extensions.Configuration; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerInvitedToCourseEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerInvitedToCourseEventHandler.cs index 12a89627f..db5fc6cc4 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerInvitedToCourseEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerInvitedToCourseEventHandler.cs @@ -1,8 +1,7 @@ using System; using System.Threading.Tasks; -using HwProj.CoursesService.API.Events; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models.NotificationsService; +using HwProj.NotificationService.Events.CoursesService; using HwProj.NotificationsService.API.Models; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerRejectToCourseEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerRejectToCourseEventHandler.cs index 00e02cdf1..e0eaa682e 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerRejectToCourseEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/LecturerRejectToCourseEventHandler.cs @@ -1,9 +1,9 @@ using System; using System.Threading.Tasks; using HwProj.AuthService.Client; -using HwProj.CoursesService.API.Events; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models.NotificationsService; +using HwProj.NotificationService.Events.CoursesService; +using HwProj.NotificationsService.API.Models; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; using Microsoft.Extensions.Configuration; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewCourseMateHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewCourseMateHandler.cs index f3f755d44..7c3930738 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewCourseMateHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewCourseMateHandler.cs @@ -3,7 +3,6 @@ using HwProj.AuthService.Client; using HwProj.CoursesService.API.Events; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models.NotificationsService; using HwProj.NotificationsService.API.Models; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewHomeworkEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewHomeworkEventHandler.cs index dd7279356..ff67ca7d8 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewHomeworkEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewHomeworkEventHandler.cs @@ -2,9 +2,9 @@ using System.Threading.Tasks; using HwProj.AuthService.Client; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models.NotificationsService; +using HwProj.NotificationService.Events.CoursesService; +using HwProj.NotificationsService.API.Models; using HwProj.NotificationsService.API.Repositories; -using HwProj.CoursesService.API.Events; using HwProj.NotificationsService.API.Services; using Microsoft.Extensions.Configuration; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewHomeworkTaskEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewHomeworkTaskEventHandler.cs index 7a157b48a..3a1a5b838 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewHomeworkTaskEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/NewHomeworkTaskEventHandler.cs @@ -2,9 +2,9 @@ using System.Threading.Tasks; using HwProj.AuthService.Client; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models.NotificationsService; +using HwProj.NotificationService.Events.CoursesService; +using HwProj.NotificationsService.API.Models; using HwProj.NotificationsService.API.Repositories; -using HwProj.CoursesService.API.Events; using HwProj.NotificationsService.API.Services; using Microsoft.Extensions.Configuration; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/PasswordRecoveryEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/PasswordRecoveryEventHandler.cs index 9f8711bce..2fecadac9 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/PasswordRecoveryEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/PasswordRecoveryEventHandler.cs @@ -1,10 +1,9 @@ using System; using System.Threading.Tasks; using System.Web; -using HwProj.AuthService.API.Events; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models; -using HwProj.Models.NotificationsService; +using HwProj.NotificationService.Events.AuthService; +using HwProj.NotificationsService.API.Models; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; using Microsoft.AspNetCore.Hosting; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/RateEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/RateEventHandler.cs index d473b5cf2..4f64911ea 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/RateEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/RateEventHandler.cs @@ -2,10 +2,10 @@ using System.Threading.Tasks; using HwProj.AuthService.Client; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models.NotificationsService; +using HwProj.NotificationService.Events.SolutionsService; +using HwProj.NotificationsService.API.Models; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; -using HwProj.SolutionsService.API.Events; using Microsoft.Extensions.Configuration; namespace HwProj.NotificationsService.API.EventHandlers diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/RegisterEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/RegisterEventHandler.cs index a15018679..322156d59 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/RegisterEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/RegisterEventHandler.cs @@ -1,9 +1,9 @@ using System; using System.Threading.Tasks; using System.Web; -using HwProj.AuthService.API.Events; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models.NotificationsService; +using HwProj.NotificationService.Events.AuthService; +using HwProj.NotificationsService.API.Models; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; using Microsoft.AspNetCore.Hosting; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/StudentPassTaskEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/StudentPassTaskEventHandler.cs index 01e610012..44fa6d736 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/StudentPassTaskEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/StudentPassTaskEventHandler.cs @@ -1,11 +1,9 @@ using System.Threading.Tasks; using HwProj.AuthService.Client; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models.NotificationsService; +using HwProj.NotificationService.Events.SolutionsService; using HwProj.NotificationsService.API.Models; -using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; -using HwProj.SolutionsService.API.Events; using Microsoft.Extensions.Configuration; namespace HwProj.NotificationsService.API.EventHandlers diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/UpdateHomeworkEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/UpdateHomeworkEventHandler.cs index 06f98170a..e0432c7b0 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/UpdateHomeworkEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/UpdateHomeworkEventHandler.cs @@ -2,9 +2,9 @@ using System.Threading.Tasks; using HwProj.AuthService.Client; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models.NotificationsService; +using HwProj.NotificationService.Events.CoursesService; +using HwProj.NotificationsService.API.Models; using HwProj.NotificationsService.API.Repositories; -using HwProj.CoursesService.API.Events; using HwProj.NotificationsService.API.Services; using Microsoft.Extensions.Configuration; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/UpdateTaskMaxRatingEventHandler.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/UpdateTaskMaxRatingEventHandler.cs index 2a6963f20..712c82f08 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/UpdateTaskMaxRatingEventHandler.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/EventHandlers/UpdateTaskMaxRatingEventHandler.cs @@ -3,10 +3,10 @@ using AutoMapper; using HwProj.AuthService.Client; using HwProj.EventBus.Client.Interfaces; -using HwProj.Models.NotificationsService; using HwProj.NotificationsService.API.Repositories; -using HwProj.CoursesService.API.Events; using HwProj.Models.AuthService.DTO; +using HwProj.NotificationService.Events.CoursesService; +using HwProj.NotificationsService.API.Models; using HwProj.NotificationsService.API.Services; using Microsoft.Extensions.Configuration; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/HwProj.NotificationsService.API.csproj b/HwProj.NotificationsService/HwProj.NotificationsService.API/HwProj.NotificationsService.API.csproj index 24abc2bd8..f1ac03115 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/HwProj.NotificationsService.API.csproj +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/HwProj.NotificationsService.API.csproj @@ -1,34 +1,25 @@  - netcoreapp2.2 + net8.0 ..\..\docker-compose.dcproj Linux ..\.. $(CSharpLanguageVersion) - $(NullableReferenceTypes) + disable - + + + - - - - - - - - - - - - - - + + + diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Models/Notification.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Models/Notification.cs new file mode 100644 index 000000000..c2c23d3d7 --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/Models/Notification.cs @@ -0,0 +1,21 @@ +using System; +using System.ComponentModel.DataAnnotations; +using HwProj.Repositories.Net8; + +namespace HwProj.NotificationsService.API.Models +{ + public class Notification : IEntity + { + [Key] public long Id { get; set; } + + public string Sender { get; set; } + + //навесить индекс + public string Owner { get; set; } + public CategoryState Category { get; set; } + public string Body { get; set; } + public bool HasSeen { get; set; } + //TODO: выставлять автоматически + public DateTime Date { get ; set; } + } +} diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Models/NotificationCategoryState.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Models/NotificationCategoryState.cs new file mode 100644 index 000000000..be3411fa4 --- /dev/null +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/Models/NotificationCategoryState.cs @@ -0,0 +1,10 @@ +namespace HwProj.NotificationsService.API.Models +{ + public enum CategoryState + { + None, + Profile, + Courses, + Homeworks + } +} \ No newline at end of file diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Models/NotificationsContext.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Models/NotificationsContext.cs index d5ae11961..d199b7899 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/Models/NotificationsContext.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/Models/NotificationsContext.cs @@ -1,5 +1,4 @@ -using HwProj.Models.NotificationsService; -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; namespace HwProj.NotificationsService.API.Models { diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Repositories/INotificationsRepository.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Repositories/INotificationsRepository.cs index 8742cccc0..cec3973f6 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/Repositories/INotificationsRepository.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/Repositories/INotificationsRepository.cs @@ -1,8 +1,8 @@ using System; using System.Linq.Expressions; using System.Threading.Tasks; -using HwProj.Models.NotificationsService; -using HwProj.Repositories; +using HwProj.NotificationsService.API.Models; +using HwProj.Repositories.Net8; namespace HwProj.NotificationsService.API.Repositories { diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Repositories/NotificationsRepository.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Repositories/NotificationsRepository.cs index 701cff308..fee37b6b7 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/Repositories/NotificationsRepository.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/Repositories/NotificationsRepository.cs @@ -2,9 +2,8 @@ using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; -using HwProj.Models.NotificationsService; using HwProj.NotificationsService.API.Models; -using HwProj.Repositories; +using HwProj.Repositories.Net8; using Microsoft.EntityFrameworkCore; using Z.EntityFramework.Plus; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Services/EmailService.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Services/EmailService.cs index ee3a38fb3..f36f0d35e 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/Services/EmailService.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/Services/EmailService.cs @@ -1,7 +1,7 @@ using System; using System.Threading.Tasks; using Autofac.Core; -using HwProj.Models.NotificationsService; +using HwProj.NotificationsService.API.Models; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using MimeKit; diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Services/IEmailService.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Services/IEmailService.cs index b2dcbdc86..37568aabe 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/Services/IEmailService.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/Services/IEmailService.cs @@ -1,5 +1,5 @@ -using HwProj.Models.NotificationsService; -using System.Threading.Tasks; +using System.Threading.Tasks; +using HwProj.NotificationsService.API.Models; namespace HwProj.NotificationsService.API.Services { diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/Startup.cs b/HwProj.NotificationsService/HwProj.NotificationsService.API/Startup.cs index 0090ac0eb..f15b72ff4 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/Startup.cs +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/Startup.cs @@ -1,19 +1,21 @@ -using HwProj.AuthService.API.Events; +using System.Text.Json.Serialization; using HwProj.AuthService.Client; +using HwProj.Common.Net8; using HwProj.EventBus.Client.Interfaces; using HwProj.NotificationsService.API.EventHandlers; using HwProj.NotificationsService.API.Models; using HwProj.NotificationsService.API.Repositories; using HwProj.NotificationsService.API.Services; -using HwProj.Utils.Configuration; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using HwProj.CoursesService.API.Events; -using HwProj.SolutionsService.API.Events; -using UpdateTaskMaxRatingEvent = HwProj.CoursesService.API.Events.UpdateTaskMaxRatingEvent; +using HwProj.EventBus.Client; +using HwProj.NotificationService.Events.AuthService; +using HwProj.NotificationService.Events.CoursesService; +using HwProj.NotificationService.Events.SolutionsService; +using Microsoft.Extensions.Hosting; +using UpdateTaskMaxRatingEvent = HwProj.NotificationService.Events.CoursesService.UpdateTaskMaxRatingEvent; namespace HwProj.NotificationsService.API { @@ -51,10 +53,16 @@ public void ConfigureServices(IServiceCollection services) services.AddHttpClient(); services.AddAuthServiceClient(); - services.ConfigureHwProjServices("Notifications API"); + services + .AddCors() + .AddControllers() + .AddJsonOptions(options => + options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles); + + services.AddAutoMapper(x => x.AddProfile()); } - public void Configure(IApplicationBuilder app, IHostingEnvironment env, IEventBus eventBus, + public void Configure(IApplicationBuilder app, IHostEnvironment env, IEventBus eventBus, NotificationsContext context) { using (var eventBustSubscriber = eventBus.CreateSubscriber()) @@ -74,7 +82,19 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, IEventBu eventBustSubscriber.Subscribe(); } - app.ConfigureHwProj(env, "Notifications API", context); + if (env.IsDevelopment()) app.UseDeveloperExceptionPage(); + else app.UseHsts(); + + app.UseRouting(); + app.UseCors(x => x + .AllowAnyMethod() + .AllowAnyHeader() + .SetIsOriginAllowed(_ => true) + .AllowCredentials()); + + app.UseEndpoints(x => x.MapControllers()); + + app.UseDatabase(env, context); } } } diff --git a/HwProj.NotificationsService/HwProj.NotificationsService.API/appsettings.json b/HwProj.NotificationsService/HwProj.NotificationsService.API/appsettings.json index 5136b7f60..f6fe217f3 100644 --- a/HwProj.NotificationsService/HwProj.NotificationsService.API/appsettings.json +++ b/HwProj.NotificationsService/HwProj.NotificationsService.API/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "DefaultConnectionForWindows": "Server=(localdb)\\mssqllocaldb;Database=NotificationsServiceDB;Trusted_Connection=True;MultipleActiveResultSets=True", + "DefaultConnectionForWindows": "Server=(localdb)\\mssqllocaldb;Database=NotificationsServiceDB;Trusted_Connection=True;TrustServerCertificate=true;MultipleActiveResultSets=True", "DefaultConnectionForLinux": "Server=localhost,1433;Database=NotificationsServiceDB;User ID=SA;Password=password_1234;" }, "Logging": { diff --git a/HwProj.SolutionsService/HwProj.SolutionsService.API/Dockerfile b/HwProj.SolutionsService/HwProj.SolutionsService.API/Dockerfile index e38a7af75..3a1c33e91 100644 --- a/HwProj.SolutionsService/HwProj.SolutionsService.API/Dockerfile +++ b/HwProj.SolutionsService/HwProj.SolutionsService.API/Dockerfile @@ -13,6 +13,7 @@ COPY ["HwProj.Common/HwProj.Utils/", "HwProj.Common/HwProj.Utils/"] COPY ["HwProj.EventBus/HwProj.EventBus.Client/", "HwProj.EventBus/HwProj.EventBus.Client/"] COPY ["HwProj.CoursesService/HwProj.CoursesService.Client/", "HwProj.CoursesService/HwProj.CoursesService.Client/"] COPY ["HwProj.AuthService/HwProj.AuthService.Client/", "HwProj.AuthService/HwProj.AuthService.Client/"] +COPY ["HwProj.NotificationsService/HwProj.NotificationService.Events/", "HwProj.NotificationsService/HwProj.NotificationService.Events/"] WORKDIR "/src/HwProj.SolutionsService/HwProj.SolutionsService.API" RUN dotnet publish "HwProj.SolutionsService.API.csproj" -c Release -o /app/publish diff --git a/HwProj.SolutionsService/HwProj.SolutionsService.API/HwProj.SolutionsService.API.csproj b/HwProj.SolutionsService/HwProj.SolutionsService.API/HwProj.SolutionsService.API.csproj index 3df1d2562..482ecfca2 100644 --- a/HwProj.SolutionsService/HwProj.SolutionsService.API/HwProj.SolutionsService.API.csproj +++ b/HwProj.SolutionsService/HwProj.SolutionsService.API/HwProj.SolutionsService.API.csproj @@ -31,6 +31,7 @@ + \ No newline at end of file diff --git a/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/20250909235525_SolutionIsModified.Designer.cs b/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/20250909235525_SolutionIsModified.Designer.cs new file mode 100644 index 000000000..c9ae3c707 --- /dev/null +++ b/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/20250909235525_SolutionIsModified.Designer.cs @@ -0,0 +1,74 @@ +// +using System; +using HwProj.SolutionsService.API.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace HwProj.SolutionsService.API.Migrations +{ + [DbContext(typeof(SolutionContext))] + [Migration("20250909235525_SolutionIsModified")] + partial class SolutionIsModified + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("HwProj.Models.SolutionsService.Solution", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Comment"); + + b.Property("GithubUrl"); + + b.Property("GroupId"); + + b.Property("IsModified"); + + b.Property("LecturerComment"); + + b.Property("LecturerId"); + + b.Property("PublicationDate"); + + b.Property("Rating"); + + b.Property("RatingDate"); + + b.Property("State"); + + b.Property("StudentId"); + + b.Property("TaskId"); + + b.HasKey("Id"); + + b.HasIndex("TaskId"); + + b.ToTable("Solutions"); + }); + + modelBuilder.Entity("HwProj.SolutionsService.API.Models.GithubSolutionCommit", b => + { + b.Property("Id"); + + b.Property("CommitHash"); + + b.HasKey("Id"); + + b.ToTable("LastGithubSolutionCommits"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/20250909235525_SolutionIsModified.cs b/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/20250909235525_SolutionIsModified.cs new file mode 100644 index 000000000..cbf1d0171 --- /dev/null +++ b/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/20250909235525_SolutionIsModified.cs @@ -0,0 +1,23 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace HwProj.SolutionsService.API.Migrations +{ + public partial class SolutionIsModified : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IsModified", + table: "Solutions", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsModified", + table: "Solutions"); + } + } +} diff --git a/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/SolutionContextModelSnapshot.cs b/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/SolutionContextModelSnapshot.cs index 0ba72c014..8a4e07014 100644 --- a/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/SolutionContextModelSnapshot.cs +++ b/HwProj.SolutionsService/HwProj.SolutionsService.API/Migrations/SolutionContextModelSnapshot.cs @@ -31,6 +31,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("GroupId"); + b.Property("IsModified"); + b.Property("LecturerComment"); b.Property("LecturerId"); diff --git a/HwProj.SolutionsService/HwProj.SolutionsService.API/Services/SolutionsService.cs b/HwProj.SolutionsService/HwProj.SolutionsService.API/Services/SolutionsService.cs index a2bdb7b9b..d10941c24 100644 --- a/HwProj.SolutionsService/HwProj.SolutionsService.API/Services/SolutionsService.cs +++ b/HwProj.SolutionsService/HwProj.SolutionsService.API/Services/SolutionsService.cs @@ -10,8 +10,8 @@ using HwProj.Models.CoursesService; using HwProj.Models.SolutionsService; using HwProj.Models.StatisticsService; +using HwProj.NotificationService.Events.SolutionsService; using HwProj.SolutionsService.API.Domains; -using HwProj.SolutionsService.API.Events; using HwProj.SolutionsService.API.Models; using HwProj.SolutionsService.API.Repositories; using Microsoft.EntityFrameworkCore; @@ -120,13 +120,14 @@ await _solutionsRepository if (lastSolution != null && lastSolution.State == SolutionState.Posted) { + var isModified = lastSolution.GithubUrl != solution.GithubUrl || lastSolution.Comment != solution.Comment; await _solutionsRepository.UpdateAsync(lastSolution.Id, x => new Solution { GithubUrl = solution.GithubUrl, Comment = solution.Comment, GroupId = solution.GroupId, + IsModified = isModified, State = SolutionState.Posted, - PublicationDate = solution.PublicationDate, }); solutionId = lastSolution.Id; } diff --git a/HwProj.SolutionsService/HwProj.SolutionsService.API/Startup.cs b/HwProj.SolutionsService/HwProj.SolutionsService.API/Startup.cs index abce7004f..752f0fba4 100644 --- a/HwProj.SolutionsService/HwProj.SolutionsService.API/Startup.cs +++ b/HwProj.SolutionsService/HwProj.SolutionsService.API/Startup.cs @@ -1,5 +1,6 @@ using HwProj.AuthService.Client; using HwProj.CoursesService.Client; +using HwProj.EventBus.Client; using HwProj.EventBus.Client.Interfaces; using HwProj.SolutionsService.API.Models; using HwProj.SolutionsService.API.Repositories; diff --git a/HwProj.SolutionsService/HwProj.SolutionsService.IntegrationTests/SolutionsServiceTests.cs b/HwProj.SolutionsService/HwProj.SolutionsService.IntegrationTests/SolutionsServiceTests.cs index 4605c1a13..be58f45aa 100644 --- a/HwProj.SolutionsService/HwProj.SolutionsService.IntegrationTests/SolutionsServiceTests.cs +++ b/HwProj.SolutionsService/HwProj.SolutionsService.IntegrationTests/SolutionsServiceTests.cs @@ -61,7 +61,7 @@ private CreateHomeworkViewModel GenerateCreateHomeworkViewModel() fixture.Customizations.Add(new RandomDateTimeSequenceGenerator(DateTime.UtcNow, DateTime.UtcNow.AddYears(addYears))); var result = fixture.Build() - .With(hvm => hvm.Tasks, new List()) + .With(hvm => hvm.Tasks, new List()) .With(hvm => hvm.PublicationDate, DateTime.UtcNow) .Without(hvm => hvm.DeadlineDate) .Without(hvm => hvm.PublicationDate) @@ -74,9 +74,9 @@ private CreateHomeworkViewModel GenerateCreateHomeworkViewModel() return result.Create(); } - private CreateTaskViewModel GenerateCreateTaskViewModelWithoutDeadLine() + private PostTaskViewModel GenerateCreateTaskViewModelWithoutDeadLine() { - return new Fixture().Build() + return new Fixture().Build() .With(t => t.HasDeadline, false) .Without(t => t.IsDeadlineStrict) .Without(t => t.PublicationDate) @@ -84,9 +84,9 @@ private CreateTaskViewModel GenerateCreateTaskViewModelWithoutDeadLine() .Create(); } - private CreateTaskViewModel GenerateCreateTaskViewModelWithStrictDeadLine() + private PostTaskViewModel GenerateCreateTaskViewModelWithStrictDeadLine() { - return new Fixture().Build() + return new Fixture().Build() .With(t => t.HasDeadline, true) .With(t => t.IsDeadlineStrict, true) .With(t => t.PublicationDate, DateTime.UtcNow) @@ -192,9 +192,9 @@ private SolutionsServiceClient CreateSolutionsServiceClient(string userId) var courseId = await CreateCourse(lectureCourseClient, lectureId); var newHomeworkViewModel = GenerateCreateHomeworkViewModel(); var newTaskViewModel = GenerateCreateTaskViewModelWithoutDeadLine(); - var homeworkId = await lectureCourseClient.AddHomeworkToCourse(newHomeworkViewModel, courseId); - var taskId = await lectureCourseClient.AddTask(homeworkId.Value, newTaskViewModel); - return (courseId, homeworkId.Value, taskId.Value); + var homework = await lectureCourseClient.AddHomeworkToCourse(newHomeworkViewModel, courseId); + var task = await lectureCourseClient.AddTask(homework.Value.Id, newTaskViewModel); + return (courseId, homework.Value.Id, task.Value.Id); } [Test, Explicit] @@ -404,18 +404,18 @@ public async Task PostSolutionAfterNotStrictDeadLine() var lectureCourseClient = CreateCourseServiceClient(lectureId); var courseId = await CreateCourse(lectureCourseClient, lectureId); var homeworkViewModel = GenerateCreateHomeworkViewModel(); - var homeworkId = await lectureCourseClient.AddHomeworkToCourse(homeworkViewModel, courseId); + var homework = await lectureCourseClient.AddHomeworkToCourse(homeworkViewModel, courseId); var taskViewModel = GenerateCreateTaskViewModelWithStrictDeadLine(); taskViewModel.IsDeadlineStrict = false; - var taskId = await lectureCourseClient.AddTask(homeworkId.Value, taskViewModel); + var task = await lectureCourseClient.AddTask(homework.Value.Id, taskViewModel); await SignStudentInCourse(studentCourseClient, lectureCourseClient, courseId, studentId); var solutionsClient = CreateSolutionsServiceClient(studentId); var solutionViewModel = GenerateSolutionViewModel(studentId); solutionViewModel.PublicationDate = DateTime.MaxValue; - var solutionId = await solutionsClient.PostSolution(taskId.Value, solutionViewModel); - var solutionIdGet = await solutionsClient.GetUserSolutions(taskId.Value, studentId); + var solutionId = await solutionsClient.PostSolution(task.Value.Id, solutionViewModel); + var solutionIdGet = await solutionsClient.GetUserSolutions(task.Value.Id, studentId); solutionIdGet.Should().HaveCount(1); solutionIdGet.Should().Contain(s => s.Id == solutionId); @@ -429,9 +429,9 @@ public async Task PostSolutionAfterStrictDeadLine() var lectureCourseClient = CreateCourseServiceClient(lectureId); var courseId = await CreateCourse(lectureCourseClient, lectureId); var homeworkViewModel = GenerateCreateHomeworkViewModel(); - var homeworkId = await lectureCourseClient.AddHomeworkToCourse(homeworkViewModel, courseId); + var homework = await lectureCourseClient.AddHomeworkToCourse(homeworkViewModel, courseId); var taskViewModel = GenerateCreateTaskViewModelWithStrictDeadLine(); - var taskId = await lectureCourseClient.AddTask(homeworkId.Value, taskViewModel); + var task = await lectureCourseClient.AddTask(homework.Value.Id, taskViewModel); await SignStudentInCourse(studentCourseClient, lectureCourseClient, courseId, studentId); var solutionsClient = CreateSolutionsServiceClient(studentId); @@ -439,7 +439,7 @@ public async Task PostSolutionAfterStrictDeadLine() solutionViewModel.PublicationDate = DateTime.MaxValue; Assert.ThrowsAsync(async () => - await solutionsClient.PostSolution(taskId.Value, solutionViewModel)); + await solutionsClient.PostSolution(task.Value.Id, solutionViewModel)); } [Test] diff --git a/HwProj.StudentInfo/IStudentsInfo/IStudentsInfo.csproj b/HwProj.StudentInfo/IStudentsInfo/IStudentsInfo.csproj index 27560206d..922bd9d9c 100644 --- a/HwProj.StudentInfo/IStudentsInfo/IStudentsInfo.csproj +++ b/HwProj.StudentInfo/IStudentsInfo/IStudentsInfo.csproj @@ -4,4 +4,8 @@ netstandard2.0 + + + + diff --git a/HwProj.StudentInfo/IStudentsInfo/IStudentsInformation.cs b/HwProj.StudentInfo/IStudentsInfo/IStudentsInformation.cs index 9434f588d..48f722a63 100644 --- a/HwProj.StudentInfo/IStudentsInfo/IStudentsInformation.cs +++ b/HwProj.StudentInfo/IStudentsInfo/IStudentsInformation.cs @@ -35,6 +35,6 @@ public interface IStudentsInformationProvider List GetStudentInformation(string groupName); /// Возвращает список образовательных программ - List GetProgramNames(); + Task> GetProgramNames(); } } \ No newline at end of file diff --git a/HwProj.StudentInfo/StudentsInfo.Tests/StudentsInformationTests.cs b/HwProj.StudentInfo/StudentsInfo.Tests/StudentsInformationTests.cs index 2d0e3bfee..f4954f236 100644 --- a/HwProj.StudentInfo/StudentsInfo.Tests/StudentsInformationTests.cs +++ b/HwProj.StudentInfo/StudentsInfo.Tests/StudentsInformationTests.cs @@ -22,9 +22,9 @@ public void SetUp() } [Test] - public void Constructor_ShouldPopulateProgramGroups() + public async Task Constructor_ShouldPopulateProgramGroups() { - var programNamesModels = _studentsInformation.GetProgramNames(); + var programNamesModels = await _studentsInformation.GetProgramNames(); var programNames = programNamesModels.Select(model => model.ProgramName).ToList(); Assert.IsNotEmpty(programNames); diff --git a/HwProj.StudentInfo/StudentsInfo/StudentsInformation.cs b/HwProj.StudentInfo/StudentsInfo/StudentsInformation.cs index 4c26f1c25..348495462 100644 --- a/HwProj.StudentInfo/StudentsInfo/StudentsInformation.cs +++ b/HwProj.StudentInfo/StudentsInfo/StudentsInformation.cs @@ -1,43 +1,41 @@ using System; using System.Collections.Generic; using System.Linq; -using HtmlAgilityPack; -using Novell.Directory.Ldap; +using System.Net.Http; using System.Threading.Tasks; using IStudentsInfo; +using Newtonsoft.Json; +using Novell.Directory.Ldap; namespace StudentsInfo { public class StudentsInformationProvider : IStudentsInformationProvider { - private readonly Lazy>> _lazyProgramsGroups; + private readonly Task>> _programsGroups; private readonly string _ldapHost = "ad.pu.ru"; private readonly int _ldapPort = 389; private readonly string _searchBase = "DC=ad,DC=pu,DC=ru"; + private readonly HttpClient _httpClient; private string _username; private string _password; - + public async Task> GetGroups(string programName) { - return await Task.Run(() => - { - return _lazyProgramsGroups.Value.ContainsKey(programName) - ? _lazyProgramsGroups.Value[programName] - .Aggregate((current, next) => current + "," + next) - .Split(',') - .Select(group => new GroupModel { GroupName = group.Trim() }) - .ToList() - : new List(); - }); + var programsGroups = await _programsGroups; + if (!programsGroups.TryGetValue(programName, out var groups)) + return new List(); + + return groups.Select(group => new GroupModel { GroupName = group }).ToList(); } - + public List GetStudentInformation(string groupName) { - var searchFilter = $"(&(objectClass=person)(memberOf=CN=АкадемГруппа_{groupName},OU=АкадемГруппа,OU=Группы,DC=ad,DC=pu,DC=ru))"; + var searchFilter = + $"(&(objectClass=person)(memberOf=CN=АкадемГруппа_{groupName},OU=АкадемГруппа,OU=Группы,DC=ad,DC=pu,DC=ru))"; var studentsList = new List(); LdapConnection connection = null; - + try { connection = new LdapConnection(); @@ -48,7 +46,7 @@ public List GetStudentInformation(string groupName) { return studentsList; } - + var results = connection.Search( _searchBase, LdapConnection.SCOPE_SUB, @@ -62,7 +60,7 @@ public List GetStudentInformation(string groupName) var entry = results.next(); var cn = entry.getAttribute("cn")?.StringValue; var displayName = entry.getAttribute("displayName")?.StringValue; - + if (cn != null && displayName != null) { string[] splitNames = displayName.Split(' '); @@ -81,11 +79,11 @@ public List GetStudentInformation(string groupName) { return studentsList; } - catch (LdapException ldapEx) + catch (LdapException) { return studentsList; } - catch (Exception ex) + catch (Exception) { return studentsList; } @@ -95,12 +93,11 @@ public List GetStudentInformation(string groupName) { if (connection != null && connection.Connected) { - SafeDisconnect(connection); + SafeDisconnect(connection); } } - catch (Exception ex) + catch (Exception) { - Console.WriteLine($"Error during disconnect: {ex.Message}"); } } @@ -116,71 +113,69 @@ private void SafeDisconnect(LdapConnection connection) catch (PlatformNotSupportedException) { } - catch (Exception ex) + catch (Exception) { - Console.WriteLine($"SafeDisconnect error: {ex.Message}"); } } - - public List GetProgramNames() + + public async Task> GetProgramNames() { - return _lazyProgramsGroups.Value.Keys + var programGroups = await _programsGroups; + return programGroups.Keys .Select(key => new ProgramModel { ProgramName = key }) .ToList(); } - public StudentsInformationProvider(string username, string password, string ldapHost, int ldapPort, string searchBase) + public StudentsInformationProvider(string username, string password, string ldapHost, int ldapPort, + string searchBase) { - this._username = username; - this._password = password; - this._ldapHost = ldapHost; - this._ldapPort = ldapPort; - this._searchBase = searchBase; + _username = username; + _password = password; + _ldapHost = ldapHost; + _ldapPort = ldapPort; + _searchBase = searchBase; + _httpClient = new HttpClient(); - _lazyProgramsGroups = new Lazy>>(() => + _programsGroups = Task.Run(async () => { var programsGroups = new Dictionary>(); - + try { - const string url = "https://timetable.spbu.ru/MATH?lang=ru"; - var web = new HtmlWeb(); - - web.PreRequest = request => - { - request.Headers.Add("Accept-Language", "ru"); - return true; - }; - - var doc = web.Load(url); - var programNodes = doc.DocumentNode.SelectNodes("//li[contains(@class, 'common-list-item row')]"); - - foreach (var programNode in programNodes) + var programsResponse = + await _httpClient.GetAsync( + "https://timetable.spbu.ru/api/v1/study/divisions/MATH/programs/levels"); + if (programsResponse.IsSuccessStatusCode) { - var programNameNode = programNode.SelectSingleNode(".//div[contains(@class, 'col-sm-5')]"); - var programName = programNameNode?.InnerText.Trim(); - - var titleNodes = programNode.SelectNodes(".//div[contains(@class, 'col-sm-1')]"); + var content = await programsResponse.Content.ReadAsStringAsync(); + var studyLevels = JsonConvert.DeserializeObject>(content); - if (titleNodes != null && programName != null) + foreach (var level in studyLevels) { - var titles = new List(); - foreach (var titleNode in titleNodes) + foreach (var programCombination in level.StudyProgramCombinations) { - var title = titleNode.SelectSingleNode(".//a")?.Attributes["title"]?.Value; - if (title != null) + foreach (var admissionYear in programCombination.AdmissionYears) { - titles.Add(title); - } - } + var groupsResponse = await _httpClient.GetAsync( + $"https://timetable.spbu.ru/api/v1/programs/{admissionYear.StudyProgramId}/groups"); + if (groupsResponse.IsSuccessStatusCode) + { + var groupsContent = await groupsResponse.Content.ReadAsStringAsync(); + var programGroups = JsonConvert.DeserializeObject(groupsContent); - if (programsGroups.ContainsKey(programName)) - { - programsGroups[programName].AddRange(titles); - } - else - { - programsGroups[programName] = titles; + var programName = programCombination.Name; + var groups = programGroups.Groups.Select(g => g.StudentGroupName).ToList(); + + if (programsGroups.ContainsKey(programName)) + { + programsGroups[programName].AddRange(groups); + } + else + { + programsGroups[programName] = groups; + } + } + } } } } @@ -193,5 +188,32 @@ public StudentsInformationProvider(string username, string password, string ldap return programsGroups; }); } + + private class StudyLevel + { + public string StudyLevelName { get; set; } + public List StudyProgramCombinations { get; set; } + } + + private class StudyProgramCombination + { + public string Name { get; set; } + public List AdmissionYears { get; set; } + } + + private class AdmissionYear + { + public int StudyProgramId { get; set; } + } + + private class ProgramGroups + { + public List Groups { get; set; } + } + + private class GroupInfo + { + public string StudentGroupName { get; set; } + } } -} \ No newline at end of file +} diff --git a/HwProj.sln b/HwProj.sln index 61dabe1e8..6b9064aec 100644 --- a/HwProj.sln +++ b/HwProj.sln @@ -76,6 +76,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IStudentsInfo", "HwProj.Stu EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StudentInfo.Tests", "HwProj.StudentInfo\StudentsInfo.Tests\StudentsInfo.Tests.csproj", "{8DE955D7-FD97-4F11-B6D4-414E631B9F83}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HwProj.Common.Net8", "HwProj.Common\HwProj.Common.Net8\HwProj.Common.Net8.csproj", "{6D9F7095-5E38-4FC6-9913-C4015B233656}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HwProj.NotificationService.Events", "HwProj.NotificationsService\HwProj.NotificationService.Events\HwProj.NotificationService.Events.csproj", "{C04A9D3D-B299-4534-B7B1-36DF92B1BC87}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HwProj.Repositories.Net8", "HwProj.Common\HwProj.Repositories.Net8\HwProj.Repositories.Net8.csproj", "{9E3A99DA-6975-46A7-90DB-69B708C8FF2C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -182,6 +188,18 @@ Global {8DE955D7-FD97-4F11-B6D4-414E631B9F83}.Debug|Any CPU.Build.0 = Debug|Any CPU {8DE955D7-FD97-4F11-B6D4-414E631B9F83}.Release|Any CPU.ActiveCfg = Release|Any CPU {8DE955D7-FD97-4F11-B6D4-414E631B9F83}.Release|Any CPU.Build.0 = Release|Any CPU + {6D9F7095-5E38-4FC6-9913-C4015B233656}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6D9F7095-5E38-4FC6-9913-C4015B233656}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6D9F7095-5E38-4FC6-9913-C4015B233656}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6D9F7095-5E38-4FC6-9913-C4015B233656}.Release|Any CPU.Build.0 = Release|Any CPU + {C04A9D3D-B299-4534-B7B1-36DF92B1BC87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C04A9D3D-B299-4534-B7B1-36DF92B1BC87}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C04A9D3D-B299-4534-B7B1-36DF92B1BC87}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C04A9D3D-B299-4534-B7B1-36DF92B1BC87}.Release|Any CPU.Build.0 = Release|Any CPU + {9E3A99DA-6975-46A7-90DB-69B708C8FF2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E3A99DA-6975-46A7-90DB-69B708C8FF2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E3A99DA-6975-46A7-90DB-69B708C8FF2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E3A99DA-6975-46A7-90DB-69B708C8FF2C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -212,6 +230,9 @@ Global {886E6A4F-9F11-482D-AADF-CCB1049B6C14} = {CCA598FB-F8A9-4F20-BCE5-BE21725156BD} {72A4C047-1F47-45DA-9BD6-54E62E7CFB78} = {CCA598FB-F8A9-4F20-BCE5-BE21725156BD} {8DE955D7-FD97-4F11-B6D4-414E631B9F83} = {CCA598FB-F8A9-4F20-BCE5-BE21725156BD} + {6D9F7095-5E38-4FC6-9913-C4015B233656} = {77D857A8-45C6-4432-B4BF-A2F2C9ECA7FE} + {C04A9D3D-B299-4534-B7B1-36DF92B1BC87} = {1EAEB779-E7C8-4EF9-B9A9-22CB8E3C246D} + {9E3A99DA-6975-46A7-90DB-69B708C8FF2C} = {77D857A8-45C6-4432-B4BF-A2F2C9ECA7FE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C03BF138-4A5B-4261-9495-6D3AC6CE9779} diff --git a/README.md b/README.md index 7ef8cb9fb..3616f03fb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# HwProj-2.0.1 +# 😺 HwProj-2.0.1 HwProj — это веб-сервис, созданный для автоматизации образовательного процесса и упрощения взаимодействия между студентами, преподавателями и экспертами из индустрии. Платформа предлагает простой интерфейс для совместной работы, уменьшая когнитивную нагрузку на всех участников образовательного процесса. Основной логической единицей сервиса HwProj является учебный курс, который преподаватели создают для обучения студентов. В рамках курса они @@ -8,15 +8,58 @@ HwProj — это веб-сервис, созданный для автомат Он особенно эффективен для курсов с дедлайнами по программированию и смежным дисциплинам, где важно отслеживать результаты студентов. Работы могут загружаться в виде ссылок на внешние ресурсы, такие как GitHub, или оцениваться после очной проверки. Преподаватели могут выставлять баллы за практические задания, доклады, проекты и другие виды работ. +**Для преподавателей** в HwProj реализована лента непроверенных решений: здесь содержится информация о решениях со всех курсов преподавателя, отсортированных по времени выполнения заданий с возможностью фильтрации. + +image_2025-10-27_01-34-23 + +**Для студентов** HwProj предоставляет ленту назначенных задач с информацией о дедлайнах. + +image_2025-10-27_01-34-23 + +**Внешние эксперты** в сервисе могут просматривать, комментировать и оценивать решения студентов по просьбе преподавателей. + +image_2025-10-27_01-34-23 + + Чтобы узнать больше о возможностях сервиса, ознакомьтесь с [нашей документацией](Docs/documentation.pdf). Для начала работы с сервисом предлагаем воспользоваться [инструкцией](https://docs.google.com/document/d/18W-LAuG7Dq75V2p-imF2KWIWvq8MhLl2Zr3ucLQnKCY/edit?usp=sharing). +Новости обновлений сервиса: https://t.me/hwproj. + Также мы рекомендуем скачать [интерактивную презентацию](Docs/interactive_presentation.pdf), которая наглядно демонстрирует ключевые возможности сервиса. ## Обратная связь Мы будем рады вашим вопросам, замечаниям по работе сервиса и предложениям по его улучшению. Вы можете связаться с нами, [открыв issue в репозитории](https://github.com/InteIIigeNET/HwProj-2.0.1/issues/new) или отправив сообщение в Telegram: [@yuri_ufimtsev](https://t.me/yuri_ufimtsev), [@DedSec256](https://t.me/DedSec256), [@yurii_litvinov](https://t.me/yurii_litvinov). + +## Архитектура +``` + +----------------+ + | API Gateway | + +--------+-------+ + | + v + +-----------------+-----------------+-----------------+------------------+ + | | | | | ++-------v------+ +-------v------+ +-------v------+ +-------v-------+ +-------v------+ +| Auth | | Courses | | Solutions | | Notifications | | Content | ++-------+------+ +-------+------+ +-------+------+ +-------+-------+ +-------+------+ + | | | | | + +-----------------+-----------------+-----------------+------------------+ + | (publish / subscribe, async) + +-----v-----------------------------------------+ + | RabbitMQ | + +-----------------------------------------------+ +``` + +- Auth Service - отвечает за регистрацию/аутентификацию и работу с данными пользователей +- Courses Service - управляет курсами, заданиями и студентами +- Solutions Service - обрабатывает отправленные студентами решения +- Notifications Service - отвечает за настройку и отправку уведомлений пользователям по новым событиями в HwProj +- Content Service - хранит информацию о прикрепленных материалах (файлах) в заданиях курса и решениях, отправляет файлы во внешнее S3-хранилище +- API Gateway - авторизует пользователей, агрегирует и постобрабатывает данные внутренних сервисов для отправки клиенту + ## Локальная сборка и запуск ### Подготовка окружения -- [.NET Core 2.2 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/2.2) +- [.NET 8 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/sdk-8.0.414-windows-x64-installer) - [MS SQL LocalDB](https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/sql-server-express-localdb?view=sql-server-ver16) - - После скачивания SQL Server Installer запускаем его, выбираем Download Media, в следующем окне тыкаем на LocalDB - Node JS, [v22.14.0](https://nodejs.org/download/release/v22.14.0/) diff --git a/backups_builder.sh b/backups_builder.sh new file mode 100644 index 000000000..c4aed5da7 --- /dev/null +++ b/backups_builder.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +# Нужен для запуска через cron. Актуализировать! +BASE_PATH=/home/hwproj_user/docker/HwProj-2.0.1 + +# Загрузка переменных из .env +set -a # Экспортируем все переменные, пропуская комментарии и пустые строки +source <(grep -v '^\s*#' ${BASE_PATH}/.env | grep -v '^\s*$') || { echo "Не удалось загрузить .env файл!" >&2; exit 1; } +set +a # Останавливаем экспорт переменных + +# Проверка, загружены ли необходимые переменные окружения +REQUIRED_VARS=("MSSQL_SA_PASSWORD" "MSSQL_BACKUPS_VOLUME" "BACKUPS_STORAGE") +for VAR in "${REQUIRED_VARS[@]}"; do + [[ -z "${!VAR}" ]] && { echo "Ошибка: $VAR не задана в .env!" >&2; exit 1; } +done + +# Задаем другие необходимые переменные +CONTAINER_NAME="mssqllocaldb" + +# Устанавливаем временную зону на московское время +TZ="Europe/Moscow" +TIMESTAMP=$(TZ=$TZ date +"%d%m%Y-%H%M%S") # Формат: ДДММГГГГ-ЧЧММСС + +TMP_DIR="$BACKUPS_STORAGE/tmp_backup_$TIMESTAMP" +ARCHIVE_NAME="backup_$TIMESTAMP.tar.gz" + +# Создаем временную директорию +mkdir -p $TMP_DIR || { echo "[ERROR] Не удалось создать $TMP_DIR" >&2; exit 1; } + +# Получаем список всех БД (кроме системных) +DBS=$(docker exec $CONTAINER_NAME /opt/mssql-tools18/bin/sqlcmd \ + -S localhost \ + -U SA \ + -P "$MSSQL_SA_PASSWORD" \ + -C \ + -Q "SET NOCOUNT ON; SELECT name FROM sys.databases WHERE name NOT IN ('master','model','msdb','tempdb') AND state = 0;" \ + -h-1 \ + -W) + +# Убираем лишние символы newline и пробелы вокруг запятых для вывода +DBS_CSV=$(echo "$DBS" | tr '\n' ',' | sed 's/,$//') +echo -e "\nБэкапы будут созданы для следующих БД: $DBS_CSV" + +if [ -z "$DBS" ]; then + echo "[ERROR] Нет БД для бэкапа." >&2 + exit 1 +fi + +# Бэкап каждой БД во временную директорию +for DB in $DBS; do + BACKUP_FILE="${DB}.bak" + echo -e "\n[$(TZ=$TZ date)] Создание бэкапа $DB..." + docker exec $CONTAINER_NAME /opt/mssql-tools18/bin/sqlcmd \ + -S localhost -U SA -P "$MSSQL_SA_PASSWORD" \ + -C \ + -Q "BACKUP DATABASE [$DB] TO DISK = '/var/opt/mssql/backups/$BACKUP_FILE' WITH FORMAT, COMPRESSION, CHECKSUM;" + + # Проверка успешности выполнения + if [ $? -eq 0 ]; then + echo "[$(TZ=$TZ date)] Бэкап $BACKUP_FILE успешно создан" >> /var/log/mssql_backup.log + else + echo "[$(TZ=$TZ date)] Ошибка создания бэкапа $BACKUP_FILE !" >> /var/log/mssql_backup_error.log + exit 1 + fi + + # Копирование бэкапа из volume во временную папку на хосте + cp "$MSSQL_BACKUPS_VOLUME/$BACKUP_FILE" "$TMP_DIR/$BACKUP_FILE" +done + +# Создаем архив со всеми бэкапами +tar -czvf "$BACKUPS_STORAGE/$ARCHIVE_NAME" -C "$TMP_DIR" . || { echo "[ERROR] Ошибка создания архива!" >&2; exit 1; } + +# Удаляем временную папку с бэкапами и очищаем volume бэкапов +echo -e "\nОчищаем временные ресурсы" +rm -rf $TMP_DIR +rm -rf $MSSQL_BACKUPS_VOLUME/* + +echo -e "\n[SUCCESS] Все БД сохранены в архив: $BACKUPS_STORAGE/$ARCHIVE_NAME" + + + +# Если скрипт запущен с параметром выгрузки, вызываем скрипт для отправки бэкапа во внешнее хранилище +if [[ "$1" == *"yandex"* ]]; then + echo -e "\nВыгружаем бэкап $BACKUP_FILE на диск в Yandex" + ${BASE_PATH}/send_to_yadisk.sh "$BACKUPS_STORAGE/$ARCHIVE_NAME" +fi \ No newline at end of file diff --git a/cleanup_old_backups.sh b/cleanup_old_backups.sh new file mode 100644 index 000000000..e229a50e6 --- /dev/null +++ b/cleanup_old_backups.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# Директория для удаления файлов на диске (сервере) +TARGET_DIR="/home/hwproj_user/docker/backups_storage" +echo -e "\nУдаляем бэкапы в папке $TARGET_DIR старше 30 дней!" + +# Удаляем с диска файлы старше 30 дней, которые начинаются на backup +find "$TARGET_DIR" -type f -name 'backup*' -mtime +30 -print -exec rm {} \; + +# Директория для удаления файлов во внешнем хранилище (Яндекс.Диске) +TARGET_YANDEX_DIR="mssql_backups" +echo -e "\nУдаляем бэкапы на Яндекс.Диске в папке $TARGET_YANDEX_DIR старше 30 дней!" +rclone delete yadisk:"$TARGET_YANDEX_DIR" --min-age 30d --include 'backup*' diff --git a/docker-compose.override.yml b/docker-compose.override.yml index a2e9065e9..175487bd7 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -4,31 +4,28 @@ services: environment: SA_PASSWORD: "${MSSQL_SA_PASSWORD}" ACCEPT_EULA: "Y" - ports: - - "${MSSQL_PORT}:1434" + expose: + - "${MSSQL_PORT}" user: root volumes: - "${MSSQL_DATA_VOLUME}:/var/opt/mssql/data" + - "${MSSQL_BACKUPS_VOLUME}:/var/opt/mssql/backups" front: - environment: - - VITE_YANDEX_METRICA_ID=${YANDEX_METRICA_ID} - - WDS_SOCKET_PORT=0 - - VITE_BASE_PATH=https://hwproj.ru - - HTTPS=true - - REACT_APP_YANDEX_APPLICATION_NAME=${REACT_APP_YANDEX_APPLICATION_NAME} - - REACT_APP_YANDEX_CLIENT_ID=${REACT_APP_YANDEX_CLIENT_ID} - - REACT_APP_YANDEX_CLIENT_SECRET=${REACT_APP_YANDEX_CLIENT_SECRET} - - REACT_APP_YANDEX_AUTHORIZATION_TOKEN=${REACT_APP_YANDEX_AUTHORIZATION_TOKEN} + build: + context: ./hwproj.front + dockerfile: ./Dockerfile + args: + - VITE_YANDEX_METRICA_ID=${YANDEX_METRICA_ID} rabbitmq: container_name: rabbitmq #environment: #- RABBITMQ_DEFAULT_USER=guest #- RABBITMQ_DEFAULT_PASS=guest - ports: - - "${RABBITMQ_5672_PORT}:5672" - - "${RABBITMQ_15672_PORT}:15672" + expose: + - "${RABBITMQ_5672_PORT}" + - "${RABBITMQ_15672_PORT}" hwproj.apigateway.api: environment: @@ -50,69 +47,65 @@ services: - GoogleSheets:auth_provider_x509_cert_url=https://www.googleapis.com/oauth2/v1/certs - GoogleSheets:client_x509_cert_url=${GOOGLE_SHEETS_CLIENT_X509_CERT_URL} - GoogleSheets:private_key=${GOOGLE_SHEETS_PRIVATE_KEY} + - Security:SecurityKey=${AUTH_SERVICE_SECURITY_KEY} ports: - - "5000:5000" + - "127.0.0.1:5000:5000" hwproj.authservice.api: environment: - - ConnectionStrings:DefaultConnectionForLinux=Server=mssqllocaldb;Database=AuthServiceDB;User=sa;Password=Your_password123; + - ConnectionStrings:DefaultConnectionForLinux=Server=mssqllocaldb;Database=AuthServiceDB;User=sa;Password=Your_password123;TrustServerCertificate=true; - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_URLS=http://+:80 - EventBus:EventBusHostName=rabbitmq + - AppSettings:SecurityKey=${AUTH_SERVICE_SECURITY_KEY} - Github:ClientIdGithub=${GITHUB_CLIENT_ID} - Github:ClientSecretGithub=${GITHUB_CLIENT_SECRET} - Github:ScopeGitHub=read:user - Gtihub:OrganizationNameGithub=${GITHUB_ORGANIZATION_NAME} - ports: - - "5001:5001" - #volumes: - #- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro - #- /root/.microsoft/usersecrets:/root/.microsoft/usersecrets:ro hwproj.coursesservice.api: environment: - ConnectionStrings:DefaultConnectionForLinux=Server=mssqllocaldb;Database=CourseWorksServiceDB;MultipleActiveResultSets=True;User=sa;Password=Your_password123; - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_HTTP_PORTS=80 - EventBus:EventBusHostName=rabbitmq - Services:Auth=http://hwproj.authservice.api - ports: - - "5002:5002" + - Services:Content=http://hwproj.contentservice.api hwproj.notificationsservice.api: environment: - - ConnectionStrings:DefaultConnectionForLinux=Server=mssqllocaldb;Database=NotificationsServiceDB;MultipleActiveResultSets=True;User=sa;Password=Your_password123; - - ASPNETCORE_ENVIRONMENT=Development + - ConnectionStrings:DefaultConnectionForLinux=Server=mssqllocaldb;Database=NotificationsServiceDB;MultipleActiveResultSets=True;User=sa;Password=Your_password123;TrustServerCertificate=true; + - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_URLS=http://+:80 - EventBus:EventBusHostName=rabbitmq - Services:Auth=http://hwproj.authservice.api - Services:Courses=http://hwproj.coursesservice.api - Services:Solutions=http://hwproj.solutionsservice.api - Notification:Mail=${NOTIFICATION_MAIL} - Notification:ConnectSite=${NOTIFICATION_CONNECT_SITE} - - Notification:Password=NOTIFICATION_PASSWORD + - Notification:Password=${NOTIFICATION_PASSWORD} - Notification:Url=https://hwproj.ru - ports: - - "5006:5006" hwproj.solutionsservice.api: environment: - ConnectionStrings:DefaultConnectionForLinux=Server=mssqllocaldb;Database=SolutionServiceDB;User=sa;Password=Your_password123; - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_HTTP_PORTS=80 - EventBus:EventBusHostName=rabbitmq - Services:Auth=http://hwproj.authservice.api - Services:Courses=http://hwproj.coursesservice.api - Github:Token=${GITHUB_TOKEN} - ports: - - "5007:5007" hwproj.contentservice.api: environment: - - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_HTTP_PORTS=80 - EventBus:EventBusHostName=rabbitmq - Services:Auth=http://hwproj.authservice.api - - StorageClientConfiguration:AccessKeyId=${STORAGE_CLIENT_ACCESS_KEY_ID} - - StorageClientConfiguration:SecretKey=${STORAGE_CLIENT_SECRET_KEY} - - StorageClientConfiguration:Region=ru-central1 - - StorageClientConfiguration:ServiceURL=https://storage.yandexcloud.net - - StorageClientConfiguration:DefaultBucketName=hwproj-files - ports: - - "5008:5008" + - ExternalStorageConfiguration:AccessKeyId=${STORAGE_CLIENT_ACCESS_KEY_ID} + - ExternalStorageConfiguration:SecretKey=${STORAGE_CLIENT_SECRET_KEY} + - ExternalStorageConfiguration:Region=ru-central1 + - ExternalStorageConfiguration:ServiceURL=https://storage.yandexcloud.net + - ExternalStorageConfiguration:DefaultBucketName=hwproj-content + - LocalStorageConfiguration:Path=/app/data/ + - ConnectionStrings:DefaultConnectionForLinux=Server=mssqllocaldb;Database=ContentServiceDB;User=sa;Password=Your_password123;TrustServerCertificate=true; diff --git a/docker-compose.yml b/docker-compose.yml index d39a97c80..9021de816 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,14 +3,14 @@ services: image: mcr.microsoft.com/mssql/server:2019-latest front: - image: docker.io/intelligenet/hwproj:front-latest + # image: docker.io/intelligenet/hwproj:front-latest #image: ${DOCKER_REGISTRY-}front build: context: ./hwproj.front dockerfile: ./Dockerfile volumes: - ./hwproj.front/static_dist:/static_output - command: sh -c "cp -r /static/* /static_output" + command: sh -c "rm -rf /static_output/*; cp -r /static/* /static_output" depends_on: - hwproj.apigateway.api @@ -18,7 +18,7 @@ services: image: rabbitmq:3-management-alpine hwproj.apigateway.api: - image: docker.io/intelligenet/hwproj:apigateway-latest + # image: docker.io/intelligenet/hwproj:apigateway-latest # or #image: ${REGISTRY:-organization}/hwproj.apigateway.api:${PLATFORM:-linux}-${TAG:-tag} #image: ${DOCKER_REGISTRY-}hwprojapigatewayapi @@ -35,7 +35,7 @@ services: hwproj.authservice.api: #image: ${DOCKER_REGISTRY-}hwprojauthserviceapi - image: docker.io/intelligenet/hwproj:authservice-latest + # image: docker.io/intelligenet/hwproj:authservice-latest build: context: . dockerfile: HwProj.AuthService/HwProj.AuthService.API/Dockerfile @@ -45,7 +45,7 @@ services: hwproj.coursesservice.api: #image: ${DOCKER_REGISTRY-}hwprojcoursesserviceapi - image: docker.io/intelligenet/hwproj:coursesservice-latest + # image: docker.io/intelligenet/hwproj:coursesservice-latest build: context: . dockerfile: HwProj.CoursesService/HwProj.CoursesService.API/Dockerfile @@ -56,7 +56,7 @@ services: hwproj.notificationsservice.api: #image: ${DOCKER_REGISTRY-}hwprojnotificationsserviceapi - image: docker.io/intelligenet/hwproj:notificationsservice-latest + # image: docker.io/intelligenet/hwproj:notificationsservice-latest build: context: . dockerfile: HwProj.NotificationsService/HwProj.NotificationsService.API/Dockerfile @@ -69,7 +69,7 @@ services: hwproj.solutionsservice.api: #image: ${DOCKER_REGISTRY-}hwprojsolutionsserviceapi - image: docker.io/intelligenet/hwproj:solutionsservice-latest + # image: docker.io/intelligenet/hwproj:solutionsservice-latest build: context: . dockerfile: HwProj.SolutionsService/HwProj.SolutionsService.API/Dockerfile @@ -81,10 +81,13 @@ services: hwproj.contentservice.api: #image: ${DOCKER_REGISTRY-}hwprojcontentserviceapi - image: docker.io/intelligenet/hwproj:contentservice-latest + # image: docker.io/intelligenet/hwproj:contentservice-latest build: context: . dockerfile: HwProj.ContentService/HwProj.ContentService.API/Dockerfile + volumes: + - ./HwProj.ContentService/FilesStorage:/app/data/ depends_on: - rabbitmq - - hwproj.authservice.api \ No newline at end of file + - hwproj.authservice.api + stop_grace_period: 11m diff --git a/generate-swagger-client.ps1 b/generate-swagger-client.ps1 index a14d94b87..274c42f93 100644 --- a/generate-swagger-client.ps1 +++ b/generate-swagger-client.ps1 @@ -71,7 +71,7 @@ Write-Host "Выполняем текстовые замены в api.ts..." $apiFilePath = Join-Path $apiDestination "api.ts" if (Test-Path -Path $apiFilePath) { - $apiContent = Get-Content -Path $apiFilePath -Raw + $apiContent = Get-Content -Path $apiFilePath # 1. Замена импорта isomorphic-fetch на ESM-совместимый $apiContent = $apiContent -replace 'import\s+\*\s+as\s+isomorphicFetch\s+from\s+"isomorphic-fetch";', 'import isomorphicFetch from "isomorphic-fetch";' @@ -79,6 +79,10 @@ if (Test-Path -Path $apiFilePath) { # 2. Делаем конфигурацию опциональной $apiContent = $apiContent -replace 'configuration:\s*Configuration;', 'configuration: Configuration | undefined;' + # 3. Форматируем пробелы + $apiContent = $apiContent | ForEach {$_.TrimEnd()} + $apiContent = $apiContent -replace '\t', (' ' * 4) + # Сохраняем изменения $apiContent | Set-Content -Path $apiFilePath -Encoding UTF8 -Force } else { diff --git a/hwproj.front/.env b/hwproj.front/.env index 5704708be..bfc5c9d57 100644 --- a/hwproj.front/.env +++ b/hwproj.front/.env @@ -1,3 +1,3 @@ -VITE_BASE_PATH=http://localhost:5000 +# Переменные, необходимые для локального запуска в режиме разработки (npm run dev) VITE_YANDEX_METRICA_ID=101061418 WDS_SOCKET_PORT=0 \ No newline at end of file diff --git a/hwproj.front/Dockerfile b/hwproj.front/Dockerfile index 3561cb63a..e78fe4611 100644 --- a/hwproj.front/Dockerfile +++ b/hwproj.front/Dockerfile @@ -8,11 +8,15 @@ WORKDIR /usr/src/app COPY package*.json ./ # Устанавливаем зависимости в node_modules -RUN npm install +RUN npm install --force # Bundle app source COPY . . +# Устанвливаем переменные для production-сборки +# Актуальные значения подтягиваются из docker-compose.override.yml +ARG VITE_YANDEX_METRICA_ID + # Собираем статику в /usr/src/app/dist RUN npm run build diff --git a/hwproj.front/eslint.config.js b/hwproj.front/eslint.config.js index 45511af8e..c348ffd98 100644 --- a/hwproj.front/eslint.config.js +++ b/hwproj.front/eslint.config.js @@ -11,10 +11,11 @@ export default [ ignores: [ "node_modules", "dist", + "static_dist", "build/**/*", "*config.*", "public", - "src/api/api.ts" // Поскольку этот файл автогенерируется + "src/api/api.ts" // Поскольку этот файл автогенерируем пока ] }, diff --git a/hwproj.front/package-lock.json b/hwproj.front/package-lock.json index 00335adaa..a0882868d 100644 --- a/hwproj.front/package-lock.json +++ b/hwproj.front/package-lock.json @@ -19,6 +19,7 @@ "@mui/icons-material": "^5.10.3", "@mui/lab": "^5.0.0-alpha.99", "@mui/material": "^5.16.11", + "@mui/x-charts": "^8.2.0", "@storybook/addon-knobs": "^6.3.0", "@types/bluebird": "^3.5.36", "@types/classnames": "^2.3.1", @@ -29,7 +30,9 @@ "@types/remarkable": "^1.7.4", "@uiw/react-markdown-preview": "4.2.2", "@uiw/react-md-editor": "3.25.6", - "axios": "^0.28.0", + "avatarka": "^1.0.1", + "avatarka-react": "^1.0.1", + "axios": "^0.30.2", "bootstrap": "^4.3.1", "classnames": "^2.3.1", "color-util": "^2.2.3", @@ -44,15 +47,18 @@ "notistack": "^3.0.2", "portable-fetch": "^3.0.0", "qrcode.react": "^4.1.0", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.0.0", + "react-dom": "^18.0.0", + "react-drag-drop-files": "^3.1.0", "react-markdown": "^5.0.0", "react-query": "^3.21.1", "react-router-dom": "^6.5.0", "react-social-login-buttons": "^3.5.1", "react-syntax-highlighter": "^15.5.0", "recharts": "^2.12.3", - "rehype-sanitize": "^6.0.0" + "rehype-katex": "^7.0.1", + "rehype-sanitize": "^6.0.0", + "remark-math": "5.1.1" }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.18.6", @@ -109,14 +115,14 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" @@ -164,13 +170,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", - "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz", + "integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0", + "@babel/parser": "^7.27.1", + "@babel/types": "^7.27.1", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -180,13 +186,13 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", - "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.1.tgz", + "integrity": "sha512-WnuuDILl9oOBbKnb4L+DyODx7iC47XfzmNCpTttFsSp6hTG7XZxu60+4IO+2/hPfcGOoKbFiwoI/+zwARbNQow==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.25.9" + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -210,18 +216,18 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.0.tgz", - "integrity": "sha512-vSGCvMecvFCd/BdpGlhpXYNhhC4ccxyvQWpbGL4CWbvfEoLFWUZuSuf7s9Aw70flgQF+6vptvgK2IfOnKlRmBg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", + "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/helper-replace-supers": "^7.26.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/traverse": "^7.27.0", + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.27.1", "semver": "^6.3.1" }, "engines": { @@ -267,42 +273,42 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", - "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz", + "integrity": "sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -312,22 +318,22 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", - "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.25.9" + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", - "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "dev": true, "license": "MIT", "engines": { @@ -353,15 +359,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz", - "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/traverse": "^7.26.5" + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -371,41 +377,41 @@ } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", - "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "license": "MIT", "engines": { @@ -442,12 +448,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.1.tgz", + "integrity": "sha512-I0dZ3ZpCrJ1c04OqlNsQcKiZlsrXf/kkE4FXzID9rIOYICsAbA8mMDzhW/luRNAHdCNt7os/u8wenklZDlUVUQ==", "license": "MIT", "dependencies": { - "@babel/types": "^7.27.0" + "@babel/types": "^7.27.1" }, "bin": { "parser": "bin/babel-parser.js" @@ -559,15 +565,15 @@ } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.9.tgz", - "integrity": "sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.27.1.tgz", + "integrity": "sha512-DTxe4LBPrtFdsWzgpmbBKevg3e9PBy+dXRt19kSbucbZvL2uqtdqwwpluL1jfxYE0wIDTFp1nTy/q6gNLsxXrg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/plugin-syntax-decorators": "^7.25.9" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-decorators": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -577,13 +583,13 @@ } }, "node_modules/@babel/plugin-proposal-export-default-from": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.25.9.tgz", - "integrity": "sha512-ykqgwNfSnNOB+C8fV5X4mG3AVmvu+WVxcaU9xHHtBb7PCrPeweMmPjGsn8eMaeJg6SJuoUuZENeeSWaarWqonQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.27.1.tgz", + "integrity": "sha512-hjlsMBl1aJc5lp8MoCDEZCiYzlgdRAShOjAfRw6X+GlpLpUPU7c3XNLsKFZbQk/1cRzBlJ7CXg3xJAJMrFa1Uw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -689,13 +695,13 @@ } }, "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.9.tgz", - "integrity": "sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.27.1.tgz", + "integrity": "sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -766,13 +772,13 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", - "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -837,13 +843,13 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", - "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1283,14 +1289,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", - "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1768,17 +1774,17 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.27.0.tgz", - "integrity": "sha512-fRGGjO2UEGPjvEcyAZXRXAS8AfdaQoq7HnxAbJoAoW10B9xOKesmmndJv+Sym2a+9FHWZ9KbyyLCe9s0Sn5jtg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.27.1.tgz", + "integrity": "sha512-Q5sT5+O4QUebHdbwKedFBEwRLb02zJ7r4A5Gg2hUoLuU3FjdMcyqcywqUrLCaDsFCxzokf7u9kuy7qz51YUuAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-create-class-features-plugin": "^7.27.0", - "@babel/helper-plugin-utils": "^7.26.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/plugin-syntax-typescript": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -2020,17 +2026,17 @@ } }, "node_modules/@babel/preset-typescript": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.0.tgz", - "integrity": "sha512-vxaPFfJtHhgeOVXRKuHpHPAOgymmy8V8I65T1q53R7GCZlefKeCaTyDs3zOPHTTbmquvNlQYC5klEvWsBAtrBQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz", + "integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5", - "@babel/helper-validator-option": "^7.25.9", - "@babel/plugin-syntax-jsx": "^7.25.9", - "@babel/plugin-transform-modules-commonjs": "^7.26.3", - "@babel/plugin-transform-typescript": "^7.27.0" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -2040,9 +2046,9 @@ } }, "node_modules/@babel/register": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.25.9.tgz", - "integrity": "sha512-8D43jXtGsYmEeDvm4MWHYUpWf8iiXgWYx3fW7E7Wb7Oe6FWqJPl5K6TuFW0dOwNZzEE5rjlaSJYH9JjrUKJszA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.27.1.tgz", + "integrity": "sha512-K13lQpoV54LATKkzBpBAEu1GGSIRzxR9f4IN4V8DCDgiUMo2UDGagEZr3lPeVNJPLkWUi5JE4hCHKneVTwQlYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2086,30 +2092,30 @@ } }, "node_modules/@babel/template": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", - "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.1.tgz", + "integrity": "sha512-Fyo3ghWMqkHHpHQCoBs2VnYjR4iWFFjguTDEqA5WgZDOrFesVjMhMM2FSqTKSoUSDO1VQtavj8NFpdRBEvJTtg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", - "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz", + "integrity": "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.27.0", - "@babel/parser": "^7.27.0", - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2127,13 +2133,13 @@ } }, "node_modules/@babel/types": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", - "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", + "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -3122,21 +3128,21 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.6.9", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", - "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.0.tgz", + "integrity": "sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==", "license": "MIT", "dependencies": { "@floating-ui/utils": "^0.2.9" } }, "node_modules/@floating-ui/dom": { - "version": "1.6.13", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz", - "integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.0.tgz", + "integrity": "sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.6.0", + "@floating-ui/core": "^1.7.0", "@floating-ui/utils": "^0.2.9" } }, @@ -3422,6 +3428,53 @@ } } }, + "node_modules/@material-ui/core/node_modules/@material-ui/system": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.2.tgz", + "integrity": "sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.3", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/core/node_modules/@material-ui/utils": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", + "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, "node_modules/@material-ui/core/node_modules/csstype": { "version": "2.6.21", "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", @@ -3485,6 +3538,24 @@ } } }, + "node_modules/@material-ui/lab/node_modules/@material-ui/utils": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", + "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, "node_modules/@material-ui/pickers": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/@material-ui/pickers/-/pickers-3.3.11.tgz", @@ -3507,14 +3578,29 @@ "react-dom": "^16.8.0 || ^17.0.0" } }, - "node_modules/@material-ui/private-theming": { + "node_modules/@material-ui/styles": { "version": "5.0.0-beta.5", - "resolved": "https://registry.npmjs.org/@material-ui/private-theming/-/private-theming-5.0.0-beta.5.tgz", - "integrity": "sha512-3J642OgHUAga6CYtzWRWG3d5FKG6NMTSxXSyk0Cc85iz/Zvl3n+x7g/MCeq8VjZULv10NzkySIXdNFQi8EKmYA==", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-5.0.0-beta.5.tgz", + "integrity": "sha512-qG88DGXNWgsdO8uhmJy0qVXX7TOIvCg9v6sL6CNDluPlao1cgw5UiHBkVBDqMJIOj+KiqThWzh/akzV+oEngSQ==", + "deprecated": "Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5.", "license": "MIT", "dependencies": { "@babel/runtime": "^7.14.8", + "@emotion/hash": "^0.8.0", + "@material-ui/private-theming": "5.0.0-beta.5", + "@material-ui/types": "6.0.2", "@material-ui/utils": "5.0.0-beta.5", + "clsx": "^1.0.4", + "csstype": "^3.0.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.7.1", + "jss-plugin-camel-case": "^10.7.1", + "jss-plugin-default-unit": "^10.7.1", + "jss-plugin-global": "^10.7.1", + "jss-plugin-nested": "^10.7.1", + "jss-plugin-props-sort": "^10.7.1", + "jss-plugin-rule-value-function": "^10.7.1", + "jss-plugin-vendor-prefixer": "^10.7.1", "prop-types": "^15.7.2" }, "engines": { @@ -3534,48 +3620,20 @@ } } }, - "node_modules/@material-ui/private-theming/node_modules/@material-ui/utils": { - "version": "5.0.0-beta.5", - "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-5.0.0-beta.5.tgz", - "integrity": "sha512-wtJ3ovXWZdTAz5eLBqvMpYH/IBJb3qMQbGCyL1i00+sf7AUlAuv4QLx+QtX/siA6L7IpxUQVfqpoCpQH1eYRpQ==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.14.8", - "@types/prop-types": "^15.7.4", - "@types/react-is": "^16.7.1 || ^17.0.0", - "prop-types": "^15.7.2", - "react-is": "^17.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "react": "^17.0.2" - } + "node_modules/@material-ui/styles/node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", + "license": "MIT" }, - "node_modules/@material-ui/styles": { + "node_modules/@material-ui/styles/node_modules/@material-ui/private-theming": { "version": "5.0.0-beta.5", - "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-5.0.0-beta.5.tgz", - "integrity": "sha512-qG88DGXNWgsdO8uhmJy0qVXX7TOIvCg9v6sL6CNDluPlao1cgw5UiHBkVBDqMJIOj+KiqThWzh/akzV+oEngSQ==", - "deprecated": "Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5.", + "resolved": "https://registry.npmjs.org/@material-ui/private-theming/-/private-theming-5.0.0-beta.5.tgz", + "integrity": "sha512-3J642OgHUAga6CYtzWRWG3d5FKG6NMTSxXSyk0Cc85iz/Zvl3n+x7g/MCeq8VjZULv10NzkySIXdNFQi8EKmYA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.14.8", - "@emotion/hash": "^0.8.0", - "@material-ui/private-theming": "5.0.0-beta.5", - "@material-ui/types": "6.0.2", "@material-ui/utils": "5.0.0-beta.5", - "clsx": "^1.0.4", - "csstype": "^3.0.2", - "hoist-non-react-statics": "^3.3.2", - "jss": "^10.7.1", - "jss-plugin-camel-case": "^10.7.1", - "jss-plugin-default-unit": "^10.7.1", - "jss-plugin-global": "^10.7.1", - "jss-plugin-nested": "^10.7.1", - "jss-plugin-props-sort": "^10.7.1", - "jss-plugin-rule-value-function": "^10.7.1", - "jss-plugin-vendor-prefixer": "^10.7.1", "prop-types": "^15.7.2" }, "engines": { @@ -3595,12 +3653,6 @@ } } }, - "node_modules/@material-ui/styles/node_modules/@emotion/hash": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", - "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", - "license": "MIT" - }, "node_modules/@material-ui/styles/node_modules/@material-ui/types": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-6.0.2.tgz", @@ -3634,41 +3686,6 @@ "react": "^17.0.2" } }, - "node_modules/@material-ui/system": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.2.tgz", - "integrity": "sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.4.4", - "@material-ui/utils": "^4.11.3", - "csstype": "^2.5.2", - "prop-types": "^15.7.2" - }, - "engines": { - "node": ">=8.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/material-ui" - }, - "peerDependencies": { - "@types/react": "^16.8.6 || ^17.0.0", - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@material-ui/system/node_modules/csstype": { - "version": "2.6.21", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", - "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==", - "license": "MIT" - }, "node_modules/@material-ui/types": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", @@ -3683,24 +3700,6 @@ } } }, - "node_modules/@material-ui/utils": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", - "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.4.4", - "prop-types": "^15.7.2", - "react-is": "^16.8.0 || ^17.0.0" - }, - "engines": { - "node": ">=8.0.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" - } - }, "node_modules/@mdx-js/mdx": { "version": "1.6.22", "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz", @@ -4182,21 +4181,235 @@ "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==", "license": "MIT" }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.9.tgz", - "integrity": "sha512-OKRBiajrrxB9ATokgEQoG87Z25c67pCpYcCwmXYX8PBftC9pBfN18gnm/fh1wurSLEKIAt+QRFLFCQISrb66Jg==", - "dev": true, + "node_modules/@mui/x-charts": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-8.2.0.tgz", + "integrity": "sha512-Onf9ZrZmoTz3awrOKXtMDHqTXroGSdDJismIVQP71MHEcoOB+qvNDaekUJqkx8jGQwldTQnwDpkzXCQaiX9RRg==", "license": "MIT", - "optional": true, "dependencies": { - "@emnapi/core": "^1.4.0", - "@emnapi/runtime": "^1.4.0", - "@tybys/wasm-util": "^0.9.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", + "@babel/runtime": "^7.27.0", + "@mui/utils": "^7.0.2", + "@mui/x-charts-vendor": "8.0.0", + "@mui/x-internals": "8.2.0", + "bezier-easing": "^2.1.0", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "reselect": "^5.1.1", + "use-sync-external-store": "^1.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.15.14 || ^6.0.0 || ^7.0.0", + "@mui/system": "^5.15.14 || ^6.0.0 || ^7.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/x-charts-vendor": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@mui/x-charts-vendor/-/x-charts-vendor-8.0.0.tgz", + "integrity": "sha512-aXv0QlCTkVxSNX+sHdG92jaQMEWJFw2NuxBx599JyZ5Ij038JwdU9x0dArfPdtpdCX0A19lHKHYgZ8S0I4LpnQ==", + "license": "MIT AND ISC", + "dependencies": { + "@babel/runtime": "^7.27.0", + "@types/d3-color": "^3.1.3", + "@types/d3-delaunay": "^6.0.4", + "@types/d3-interpolate": "^3.0.4", + "@types/d3-scale": "^4.0.9", + "@types/d3-shape": "^3.1.7", + "@types/d3-time": "^3.0.4", + "@types/d3-timer": "^3.0.2", + "d3-color": "^3.1.0", + "d3-delaunay": "^6.0.4", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0", + "d3-time": "^3.1.0", + "d3-timer": "^3.0.1", + "delaunator": "^5.0.1", + "robust-predicates": "^3.0.2" + } + }, + "node_modules/@mui/x-charts-vendor/node_modules/@types/d3-shape": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@mui/x-charts/node_modules/@mui/types": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.1.tgz", + "integrity": "sha512-gUL8IIAI52CRXP/MixT1tJKt3SI6tVv4U/9soFsTtAsHzaJQptZ42ffdHZV3niX1ei0aUgMvOxBBN0KYqdG39g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.0" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/x-charts/node_modules/@mui/utils": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.0.2.tgz", + "integrity": "sha512-72gcuQjPzhj/MLmPHLCgZjy2VjOH4KniR/4qRtXTTXIEwbkgcN+Y5W/rC90rWtMmZbjt9svZev/z+QHUI4j74w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.0", + "@mui/types": "^7.4.1", + "@types/prop-types": "^15.7.14", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/x-charts/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@mui/x-charts/node_modules/react-is": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", + "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==", + "license": "MIT" + }, + "node_modules/@mui/x-internals": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.2.0.tgz", + "integrity": "sha512-qV4Qr+m4sAPBSuqu8/Ofi5m+nMMvIybGno6cp757bHSmwxkqrn5SKaGyFnH5kB58fOhYA9hG1UivFp7mO1dE4A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.0", + "@mui/utils": "^7.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@mui/x-internals/node_modules/@mui/types": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.1.tgz", + "integrity": "sha512-gUL8IIAI52CRXP/MixT1tJKt3SI6tVv4U/9soFsTtAsHzaJQptZ42ffdHZV3niX1ei0aUgMvOxBBN0KYqdG39g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.0" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/x-internals/node_modules/@mui/utils": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.0.2.tgz", + "integrity": "sha512-72gcuQjPzhj/MLmPHLCgZjy2VjOH4KniR/4qRtXTTXIEwbkgcN+Y5W/rC90rWtMmZbjt9svZev/z+QHUI4j74w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.0", + "@mui/types": "^7.4.1", + "@types/prop-types": "^15.7.14", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/x-internals/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@mui/x-internals/node_modules/react-is": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", + "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==", + "license": "MIT" + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.9.tgz", + "integrity": "sha512-OKRBiajrrxB9ATokgEQoG87Z25c67pCpYcCwmXYX8PBftC9pBfN18gnm/fh1wurSLEKIAt+QRFLFCQISrb66Jg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.0", + "@emnapi/runtime": "^1.4.0", + "@tybys/wasm-util": "^0.9.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, @@ -4698,6 +4911,68 @@ } } }, + "node_modules/@storybook/addon-knobs/node_modules/@emotion/cache": { + "version": "10.0.29", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", + "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", + "license": "MIT", + "dependencies": { + "@emotion/sheet": "0.9.4", + "@emotion/stylis": "0.8.5", + "@emotion/utils": "0.11.3", + "@emotion/weak-memoize": "0.2.5" + } + }, + "node_modules/@storybook/addon-knobs/node_modules/@emotion/sheet": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz", + "integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==", + "license": "MIT" + }, + "node_modules/@storybook/addon-knobs/node_modules/@emotion/utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", + "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==", + "license": "MIT" + }, + "node_modules/@storybook/addon-knobs/node_modules/@emotion/weak-memoize": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", + "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==", + "license": "MIT" + }, + "node_modules/@storybook/addon-knobs/node_modules/react-select": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-3.2.0.tgz", + "integrity": "sha512-B/q3TnCZXEKItO0fFN/I0tWOX3WJvi/X2wtdffmwSQVRwg5BpValScTO1vdic9AxlUgmeSzib2hAZAwIUQUZGQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@emotion/cache": "^10.0.9", + "@emotion/core": "^10.0.9", + "@emotion/css": "^10.0.9", + "memoize-one": "^5.0.0", + "prop-types": "^15.6.0", + "react-input-autosize": "^3.0.0", + "react-transition-group": "^4.3.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@storybook/addon-knobs/node_modules/react-select/node_modules/react-input-autosize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz", + "integrity": "sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.5.8" + }, + "peerDependencies": { + "react": "^16.3.0 || ^17.0.0" + } + }, "node_modules/@storybook/addons": { "version": "6.5.16", "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.5.16.tgz", @@ -5964,6 +6239,32 @@ "dev": true, "license": "MIT" }, + "node_modules/@storybook/react/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@storybook/react/node_modules/react-element-to-jsx-string": { + "version": "14.3.4", + "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-14.3.4.tgz", + "integrity": "sha512-t4ZwvV6vwNxzujDQ+37bspnLwA4JlgUPWhLjBJWsNIDceAf6ZKUTCjdm08cN6WeZ5pTMKiCJkmAYnpmR4Bm+dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@base2/pretty-print-object": "1.0.1", + "is-plain-object": "5.0.0", + "react-is": "17.0.2" + }, + "peerDependencies": { + "react": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1", + "react-dom": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1" + } + }, "node_modules/@storybook/react/node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", @@ -6659,6 +6960,12 @@ "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", "license": "MIT" }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT" + }, "node_modules/@types/d3-ease": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", @@ -6847,6 +7154,12 @@ "integrity": "sha512-aWw2YTtAdT7CskFyxEX2K21/zSDStuf/ikI3yBqmwpwJF0pS+/IX5DWv+1UFffZIbruP6cnT9/LAJV1gFwAT1A==", "license": "MIT" }, + "node_modules/@types/katex": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.7.tgz", + "integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==", + "license": "MIT" + }, "node_modules/@types/lodash": { "version": "4.17.16", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz", @@ -7075,6 +7388,12 @@ "@types/react": "*" } }, + "node_modules/@types/stylis": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz", + "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==", + "license": "MIT" + }, "node_modules/@types/tapable": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.12.tgz", @@ -7466,152 +7785,518 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/property-information": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", - "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/@uiw/react-markdown-preview/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "license": "MIT" - }, - "node_modules/@uiw/react-markdown-preview/node_modules/react-markdown": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.7.tgz", - "integrity": "sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==", + "node_modules/@uiw/react-markdown-preview/node_modules/mdast-util-from-markdown": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz", + "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==", "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0", - "@types/prop-types": "^15.0.0", + "@types/mdast": "^3.0.0", "@types/unist": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-whitespace": "^2.0.0", - "prop-types": "^15.0.0", - "property-information": "^6.0.0", - "react-is": "^18.0.0", - "remark-parse": "^10.0.0", - "remark-rehype": "^10.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-object": "^0.4.0", - "unified": "^10.0.0", - "unist-util-visit": "^4.0.0", - "vfile": "^5.0.0" + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "@types/react": ">=16", - "react": ">=16" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/remark-parse": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.2.tgz", - "integrity": "sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==", + "node_modules/@uiw/react-markdown-preview/node_modules/micromark": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz", + "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@types/mdast": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "unified": "^10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/space-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "node_modules/@uiw/react-markdown-preview/node_modules/micromark-core-commonmark": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz", + "integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/style-to-object": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", - "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", + "node_modules/@uiw/react-markdown-preview/node_modules/micromark-factory-destination": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz", + "integrity": "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "inline-style-parser": "0.1.1" + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/trough": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", - "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "node_modules/@uiw/react-markdown-preview/node_modules/micromark-factory-label": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz", + "integrity": "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/unified": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", - "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "node_modules/@uiw/react-markdown-preview/node_modules/micromark-factory-title": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz", + "integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "bail": "^2.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/unist-util-is": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", - "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "node_modules/@uiw/react-markdown-preview/node_modules/micromark-factory-whitespace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz", + "integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/unist-util-visit": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", - "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "node_modules/@uiw/react-markdown-preview/node_modules/micromark-util-chunked": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz", + "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.1.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-util-symbol": "^1.0.0" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/unist-util-visit-parents": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", - "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", - "license": "MIT", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0" + "node_modules/@uiw/react-markdown-preview/node_modules/micromark-util-classify-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz", + "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/micromark-util-combine-extensions": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz", + "integrity": "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/micromark-util-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", + "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/@uiw/react-markdown-preview/node_modules/micromark-util-html-tag-name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz", + "integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/@uiw/react-markdown-preview/node_modules/micromark-util-normalize-identifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz", + "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/micromark-util-resolve-all": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz", + "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/micromark-util-sanitize-uri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", + "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/micromark-util-subtokenize": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz", + "integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/@uiw/react-markdown-preview/node_modules/react-markdown": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.7.tgz", + "integrity": "sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/prop-types": "^15.0.0", + "@types/unist": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^2.0.0", + "prop-types": "^15.0.0", + "property-information": "^6.0.0", + "react-is": "^18.0.0", + "remark-parse": "^10.0.0", + "remark-rehype": "^10.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unified": "^10.0.0", + "unist-util-visit": "^4.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/remark-parse": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.2.tgz", + "integrity": "sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/style-to-object": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", + "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/unist-util-visit": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/unist-util-visit-parents": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" }, "funding": { "type": "opencollective", @@ -7670,24 +8355,150 @@ "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "license": "ISC" }, - "node_modules/@unrs/resolver-binding-darwin-arm64": { + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.5.0.tgz", + "integrity": "sha512-YmocNlEcX/AgJv8gI41bhjMOTcKcea4D2nRIbZj+MhRtSH5+vEU8r/pFuTuoF+JjVplLsBueU+CILfBPVISyGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.5.0.tgz", + "integrity": "sha512-qpUrXgH4e/0xu1LOhPEdfgSY3vIXOxDQv370NEL8npN8h40HcQDA+Pl2r4HBW6tTXezWIjxUFcP7tj529RZtDw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.5.0.tgz", + "integrity": "sha512-3tX8r8vgjvZzaJZB4jvxUaaFCDCb3aWDCpZN3EjhGnnwhztslI05KSG5NY/jNjlcZ5QWZ7dEZZ/rNBFsmTaSPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.5.0.tgz", + "integrity": "sha512-FH+ixzBKaUU9fWOj3TYO+Yn/eO6kYvMLV9eNJlJlkU7OgrxkCmiMS6wUbyT0KA3FOZGxnEQ2z3/BHgYm2jqeLA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.5.0.tgz", + "integrity": "sha512-pxCgXMgwB/4PfqFQg73lMhmWwcC0j5L+dNXhZoz/0ek0iS/oAWl65fxZeT/OnU7fVs52MgdP2q02EipqJJXHSg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.5.0.tgz", + "integrity": "sha512-FX2FV7vpLE/+Z0NZX9/1pwWud5Wocm/2PgpUXbT5aSV3QEB10kBPJAzssOQylvdj8mOHoKl5pVkXpbCwww/T2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.5.0.tgz", + "integrity": "sha512-+gF97xst1BZb28T3nwwzEtq2ewCoMDGKsenYsZuvpmNrW0019G1iUAunZN+FG55L21y+uP7zsGX06OXDQ/viKw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.5.0.tgz", + "integrity": "sha512-5bEmVcQw9js8JYM2LkUBw5SeELSIxX+qKf9bFrfFINKAp4noZ//hUxLpbF7u/3gTBN1GsER6xOzIZlw/VTdXtA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.5.0.tgz", + "integrity": "sha512-GGk/8TPUsf1Q99F+lzMdjE6sGL26uJCwQ9TlvBs8zR3cLQNw/MIumPN7zrs3GFGySjnwXc8gA6J3HKbejywmqA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.5.0.tgz", - "integrity": "sha512-YmocNlEcX/AgJv8gI41bhjMOTcKcea4D2nRIbZj+MhRtSH5+vEU8r/pFuTuoF+JjVplLsBueU+CILfBPVISyGQ==", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.5.0.tgz", + "integrity": "sha512-5uRkFYYVNAeVaA4W/CwugjFN3iDOHCPqsBLCCOoJiMfFMMz4evBRsg+498OFa9w6VcTn2bD5aI+RRayaIgk2Sw==", "cpu": [ - "arm64" + "s390x" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" + "linux" ] }, - "node_modules/@unrs/resolver-binding-darwin-x64": { + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.5.0.tgz", - "integrity": "sha512-qpUrXgH4e/0xu1LOhPEdfgSY3vIXOxDQv370NEL8npN8h40HcQDA+Pl2r4HBW6tTXezWIjxUFcP7tj529RZtDw==", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.5.0.tgz", + "integrity": "sha512-j905CZH3nehYy6NimNqC2B14pxn4Ltd7guKMyPTzKehbFXTUgihQS/ZfHQTdojkMzbSwBOSgq1dOrY+IpgxDsA==", "cpu": [ "x64" ], @@ -7695,13 +8506,13 @@ "license": "MIT", "optional": true, "os": [ - "darwin" + "linux" ] }, - "node_modules/@unrs/resolver-binding-freebsd-x64": { + "node_modules/@unrs/resolver-binding-linux-x64-musl": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.5.0.tgz", - "integrity": "sha512-3tX8r8vgjvZzaJZB4jvxUaaFCDCb3aWDCpZN3EjhGnnwhztslI05KSG5NY/jNjlcZ5QWZ7dEZZ/rNBFsmTaSPw==", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.5.0.tgz", + "integrity": "sha512-dmLevQTuzQRwu5A+mvj54R5aye5I4PVKiWqGxg8tTaYP2k2oTs/3Mo8mgnhPk28VoYCi0fdFYpgzCd4AJndQvQ==", "cpu": [ "x64" ], @@ -7709,808 +8520,1095 @@ "license": "MIT", "optional": true, "os": [ - "freebsd" + "linux" ] }, - "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "node_modules/@unrs/resolver-binding-wasm32-wasi": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.5.0.tgz", - "integrity": "sha512-FH+ixzBKaUU9fWOj3TYO+Yn/eO6kYvMLV9eNJlJlkU7OgrxkCmiMS6wUbyT0KA3FOZGxnEQ2z3/BHgYm2jqeLA==", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.5.0.tgz", + "integrity": "sha512-LtJMhwu7avhoi+kKfAZOKN773RtzLBVVF90YJbB0wyMpUj9yQPeA+mteVUI9P70OG/opH47FeV5AWeaNWWgqJg==", "cpu": [ - "arm" + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.8" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.5.0.tgz", + "integrity": "sha512-FTZBxLL4SO1mgIM86KykzJmPeTPisBDHQV6xtfDXbTMrentuZ6SdQKJUV5BWaoUK3p8kIULlrCcucqdCnk8Npg==", + "cpu": [ + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ] }, - "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.5.0.tgz", - "integrity": "sha512-pxCgXMgwB/4PfqFQg73lMhmWwcC0j5L+dNXhZoz/0ek0iS/oAWl65fxZeT/OnU7fVs52MgdP2q02EipqJJXHSg==", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.5.0.tgz", + "integrity": "sha512-i5bB7vJ1waUsFciU/FKLd4Zw0VnAkvhiJ4//jYQXyDUuiLKodmtQZVTcOPU7pp97RrNgCFtXfC1gnvj/DHPJTw==", "cpu": [ - "arm" + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.5.0.tgz", + "integrity": "sha512-wAvXp4k7jhioi4SebXW/yfzzYwsUCr9kIX4gCsUFKpCTUf8Mi7vScJXI3S+kupSUf0LbVHudR8qBbe2wFMSNUw==", + "cpu": [ + "x64" ], "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.4.1.tgz", + "integrity": "sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.26.10", + "@babel/plugin-transform-react-jsx-self": "^7.25.9", + "@babel/plugin-transform-react-jsx-source": "^7.25.9", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "node_modules/@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==", + "dev": true, + "license": "ISC" + }, + "node_modules/@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } }, - "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.5.0.tgz", - "integrity": "sha512-FX2FV7vpLE/+Z0NZX9/1pwWud5Wocm/2PgpUXbT5aSV3QEB10kBPJAzssOQylvdj8mOHoKl5pVkXpbCwww/T2g==", - "cpu": [ - "arm64" - ], + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } }, - "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.5.0.tgz", - "integrity": "sha512-+gF97xst1BZb28T3nwwzEtq2ewCoMDGKsenYsZuvpmNrW0019G1iUAunZN+FG55L21y+uP7zsGX06OXDQ/viKw==", - "cpu": [ - "arm64" - ], + "node_modules/@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } }, - "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.5.0.tgz", - "integrity": "sha512-5bEmVcQw9js8JYM2LkUBw5SeELSIxX+qKf9bFrfFINKAp4noZ//hUxLpbF7u/3gTBN1GsER6xOzIZlw/VTdXtA==", - "cpu": [ - "ppc64" - ], + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } }, - "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.5.0.tgz", - "integrity": "sha512-GGk/8TPUsf1Q99F+lzMdjE6sGL26uJCwQ9TlvBs8zR3cLQNw/MIumPN7zrs3GFGySjnwXc8gA6J3HKbejywmqA==", - "cpu": [ - "riscv64" - ], + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "license": "BSD-3-Clause" }, - "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.5.0.tgz", - "integrity": "sha512-5uRkFYYVNAeVaA4W/CwugjFN3iDOHCPqsBLCCOoJiMfFMMz4evBRsg+498OFa9w6VcTn2bD5aI+RRayaIgk2Sw==", - "cpu": [ - "s390x" - ], + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "license": "Apache-2.0" }, - "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.5.0.tgz", - "integrity": "sha512-j905CZH3nehYy6NimNqC2B14pxn4Ltd7guKMyPTzKehbFXTUgihQS/ZfHQTdojkMzbSwBOSgq1dOrY+IpgxDsA==", - "cpu": [ - "x64" - ], + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } }, - "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.5.0.tgz", - "integrity": "sha512-dmLevQTuzQRwu5A+mvj54R5aye5I4PVKiWqGxg8tTaYP2k2oTs/3Mo8mgnhPk28VoYCi0fdFYpgzCd4AJndQvQ==", - "cpu": [ - "x64" - ], + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": ">= 0.6" + } }, - "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.5.0.tgz", - "integrity": "sha512-LtJMhwu7avhoi+kKfAZOKN773RtzLBVVF90YJbB0wyMpUj9yQPeA+mteVUI9P70OG/opH47FeV5AWeaNWWgqJg==", - "cpu": [ - "wasm32" - ], + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true, "license": "MIT", - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.8" + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">=14.0.0" + "node": ">=0.4.0" } }, - "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.5.0.tgz", - "integrity": "sha512-FTZBxLL4SO1mgIM86KykzJmPeTPisBDHQV6xtfDXbTMrentuZ6SdQKJUV5BWaoUK3p8kIULlrCcucqdCnk8Npg==", - "cpu": [ - "arm64" - ], + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } }, - "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.5.0.tgz", - "integrity": "sha512-i5bB7vJ1waUsFciU/FKLd4Zw0VnAkvhiJ4//jYQXyDUuiLKodmtQZVTcOPU7pp97RrNgCFtXfC1gnvj/DHPJTw==", - "cpu": [ - "ia32" - ], + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "engines": { + "node": ">=0.4.0" + } }, - "node_modules/@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.5.0.tgz", - "integrity": "sha512-wAvXp4k7jhioi4SebXW/yfzzYwsUCr9kIX4gCsUFKpCTUf8Mi7vScJXI3S+kupSUf0LbVHudR8qBbe2wFMSNUw==", - "cpu": [ - "x64" - ], + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "engines": { + "node": ">= 10.0.0" + } }, - "node_modules/@vitejs/plugin-react": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.4.1.tgz", - "integrity": "sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w==", + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.26.10", - "@babel/plugin-transform-react-jsx-self": "^7.25.9", - "@babel/plugin-transform-react-jsx-source": "^7.25.9", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" }, "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" + "node": ">=8" } }, - "node_modules/@vitejs/plugin-react/node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "node_modules/airbnb-js-shims": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/airbnb-js-shims/-/airbnb-js-shims-2.2.1.tgz", + "integrity": "sha512-wJNXPH66U2xjgo1Zwyjf9EydvJ2Si94+vSdk6EERcBfB2VZkeltpqIats0cqIZMLCXP3zcyaUKGYQeIBT6XjsQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "array-includes": "^3.0.3", + "array.prototype.flat": "^1.2.1", + "array.prototype.flatmap": "^1.2.1", + "es5-shim": "^4.5.13", + "es6-shim": "^0.35.5", + "function.prototype.name": "^1.1.0", + "globalthis": "^1.0.0", + "object.entries": "^1.1.0", + "object.fromentries": "^2.0.0 || ^1.0.0", + "object.getownpropertydescriptors": "^2.0.3", + "object.values": "^1.1.0", + "promise.allsettled": "^1.0.0", + "promise.prototype.finally": "^3.1.0", + "string.prototype.matchall": "^4.0.0 || ^3.0.1", + "string.prototype.padend": "^3.0.0", + "string.prototype.padstart": "^3.0.0", + "symbol.prototype.description": "^1.0.0" } }, - "node_modules/@webassemblyjs/ast": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", - "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/helper-module-context": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/wast-parser": "1.9.0" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", - "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", - "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", - "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==", + "node_modules/ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peerDependencies": { + "ajv": ">=5.0.0" + } }, - "node_modules/@webassemblyjs/helper-code-frame": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", - "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/wast-printer": "1.9.0" + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "node_modules/@webassemblyjs/helper-fsm": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", - "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==", - "dev": true, - "license": "ISC" - }, - "node_modules/@webassemblyjs/helper-module-context": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", - "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.9.0" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", - "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==", + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, "license": "MIT" }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", - "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0" + "peerDependencies": { + "ajv": "^6.9.1" } }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", - "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@xtuc/ieee754": "^1.2.0" + "string-width": "^4.1.0" } }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", - "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "node_modules/ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", "dev": true, "license": "MIT", - "dependencies": { - "@xtuc/long": "4.2.2" + "engines": { + "node": ">=6" } }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", - "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", + "node_modules/ansi-html": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.9.tgz", + "integrity": "sha512-ozbS3LuenHVxNRh/wdnN16QapUHzauqSomAl1jwwJRRsGwFwtj644lIhxfWu0Fy0acCij2+AEgHvjscq3dlVXg==", "dev": true, - "license": "MIT" + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", - "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/helper-wasm-section": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0", - "@webassemblyjs/wasm-opt": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0", - "@webassemblyjs/wast-printer": "1.9.0" + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" } }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", - "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/ieee754": "1.9.0", - "@webassemblyjs/leb128": "1.9.0", - "@webassemblyjs/utf8": "1.9.0" + "engines": { + "node": ">=8" } }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", - "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", - "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "node_modules/ansi-to-html": { + "version": "0.6.15", + "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.15.tgz", + "integrity": "sha512-28ijx2aHJGdzbs+O5SNQF65r6rrKYnkuwTYm8lZlChuoJ9P1vVzIpWO20sQTqTPDXYp6NFwk326vApTtLVFXpQ==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-api-error": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/ieee754": "1.9.0", - "@webassemblyjs/leb128": "1.9.0", - "@webassemblyjs/utf8": "1.9.0" + "entities": "^2.0.0" + }, + "bin": { + "ansi-to-html": "bin/ansi-to-html" + }, + "engines": { + "node": ">=8.0.0" } }, - "node_modules/@webassemblyjs/wast-parser": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", - "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/floating-point-hex-parser": "1.9.0", - "@webassemblyjs/helper-api-error": "1.9.0", - "@webassemblyjs/helper-code-frame": "1.9.0", - "@webassemblyjs/helper-fsm": "1.9.0", - "@xtuc/long": "4.2.2" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", - "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "node_modules/app-root-dir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/app-root-dir/-/app-root-dir-1.0.2.tgz", + "integrity": "sha512-jlpIfsOoNoafl92Sz//64uQHGSyMrD2vYG5d8o2a4qGvyNCvXur7bzIsWtAC/6flI2RYAp3kv8rsfBtaLm7w0g==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/wast-parser": "1.9.0", - "@xtuc/long": "4.2.2" + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "license": "BSD-3-Clause" + "license": "Python-2.0" }, - "node_modules/@xtuc/long": { + "node_modules/aria-query": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" }, "engines": { - "node": ">= 0.6" + "node": ">=6.0" } }, - "node_modules/accepts/node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true, "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, "engines": { - "node": ">=0.4.0" + "node": ">=0.10.0" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", "dev": true, "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, "engines": { - "node": ">=0.4.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/address": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", - "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "node_modules/array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", "dev": true, "license": "MIT", + "optional": true, "engines": { - "node": ">= 10.0.0" + "node": ">=0.10.0" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, "license": "MIT", "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/airbnb-js-shims": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/airbnb-js-shims/-/airbnb-js-shims-2.2.1.tgz", - "integrity": "sha512-wJNXPH66U2xjgo1Zwyjf9EydvJ2Si94+vSdk6EERcBfB2VZkeltpqIats0cqIZMLCXP3zcyaUKGYQeIBT6XjsQ==", + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", "dev": true, "license": "MIT", - "dependencies": { - "array-includes": "^3.0.3", - "array.prototype.flat": "^1.2.1", - "array.prototype.flatmap": "^1.2.1", - "es5-shim": "^4.5.13", - "es6-shim": "^0.35.5", - "function.prototype.name": "^1.1.0", - "globalthis": "^1.0.0", - "object.entries": "^1.1.0", - "object.fromentries": "^2.0.0 || ^1.0.0", - "object.getownpropertydescriptors": "^2.0.3", - "object.values": "^1.1.0", - "promise.allsettled": "^1.0.0", - "promise.prototype.finally": "^3.1.0", - "string.prototype.matchall": "^4.0.0 || ^3.0.1", - "string.prototype.padend": "^3.0.0", - "string.prototype.padstart": "^3.0.0", - "symbol.prototype.description": "^1.0.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", "dev": true, "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/ajv-errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", "dev": true, "license": "MIT", - "peerDependencies": { - "ajv": ">=5.0.0" + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "^8.0.0" + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" }, - "peerDependencies": { - "ajv": "^8.0.0" + "engines": { + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "dev": true, "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "license": "ISC", "dependencies": { - "string-width": "^4.1.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "node_modules/array.prototype.map": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.8.tgz", + "integrity": "sha512-YocPM7bYYu2hXGxWpb5vwZ8cMeudNHYtYBcUDY4Z1GWa53qcnQMWSl25jeBHNzitjl9HW2AWW4ro/S/nftUaOQ==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-array-method-boxes-properly": "^1.0.0", + "es-object-atoms": "^1.0.0", + "is-string": "^1.1.1" + }, "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-html": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.9.tgz", - "integrity": "sha512-ozbS3LuenHVxNRh/wdnN16QapUHzauqSomAl1jwwJRRsGwFwtj644lIhxfWu0Fy0acCij2+AEgHvjscq3dlVXg==", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "license": "Apache-2.0", - "bin": { - "ansi-html": "bin/ansi-html" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "node_modules/array.prototype.reduce": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.8.tgz", + "integrity": "sha512-DwuEqgXFBwbmZSRqt3BpQigWNUoqw9Ml2dTWdF3B2zQlQX4OeUE0zyuzX0fX0IbTvjdkZbcBTU3idgpO78qkTw==", "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "license": "Apache-2.0", - "bin": { - "ansi-html": "bin/ansi-html" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-array-method-boxes-properly": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "is-string": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ansi-to-html": { - "version": "0.6.15", - "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.15.tgz", - "integrity": "sha512-28ijx2aHJGdzbs+O5SNQF65r6rrKYnkuwTYm8lZlChuoJ9P1vVzIpWO20sQTqTPDXYp6NFwk326vApTtLVFXpQ==", + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", "dev": true, "license": "MIT", - "dependencies": { - "entities": "^2.0.0" - }, - "bin": { - "ansi-to-html": "bin/ansi-to-html" - }, "engines": { - "node": ">=8.0.0" + "node": ">=8" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, - "node_modules/app-root-dir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/app-root-dir/-/app-root-dir-1.0.2.tgz", - "integrity": "sha512-jlpIfsOoNoafl92Sz//64uQHGSyMrD2vYG5d8o2a4qGvyNCvXur7bzIsWtAC/6flI2RYAp3kv8rsfBtaLm7w0g==", + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", "dev": true, "license": "MIT" }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "node_modules/assert": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.1.tgz", + "integrity": "sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "object.assign": "^4.1.4", + "util": "^0.10.4" + } + }, + "node_modules/assert/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true, "license": "ISC" }, - "node_modules/are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "deprecated": "This package is no longer supported.", + "node_modules/assert/node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ast-types": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", + "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" + "tslib": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=4" } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "node_modules/async-each": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", + "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", "dev": true, - "license": "Python-2.0" + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "optional": true }, - "node_modules/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" - }, + "license": "MIT", "engines": { - "node": ">=6.0" + "node": ">= 0.4" } }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">=0.10.0" + "node": ">= 4.0.0" } }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true, - "license": "MIT", + "license": "(MIT OR Apache-2.0)", + "bin": { + "atob": "bin/atob.js" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 4.5.0" } }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "node_modules/autoprefixer": { + "version": "9.8.8", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.8.tgz", + "integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "picocolors": "^0.2.1", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" } }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "node_modules/autoprefixer/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true, + "license": "ISC" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" + "possible-typed-array-names": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -8519,503 +9617,544 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", - "dev": true, + "node_modules/avatarka": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/avatarka/-/avatarka-1.0.1.tgz", + "integrity": "sha512-uFRzGLP+6pALoT3D9ckNcaub7AtL8fUfS3l9jwzIj66PyQ6OqfbP4HrFLlpgDXIJ09Z7q7Xx+ltDqIFHW3MNcw==", "license": "MIT", - "optional": true, "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/array-includes": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", - "dev": true, + "node_modules/avatarka-react": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/avatarka-react/-/avatarka-react-1.0.1.tgz", + "integrity": "sha512-tF4P5HJezV2wVk3+D/8EbYG6A+wpdpXQak7JIQynKsFfJu14SRJoWRwHGZ5TOK/fjLjbPYWNrA5PHkGGaWtvVw==", "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" + "avatarka": "^1.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "node_modules/axios": { + "version": "0.30.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.30.2.tgz", + "integrity": "sha512-0pE4RQ4UQi1jKY6p7u6i1Tkzqmu+d+/tHS7Q7rKunWLB9WyilBTpHHpXzPNMDj5hTbK0B0PTLSz07yqMBiF6xg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-loader": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.4.1.tgz", + "integrity": "sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==", "dev": true, "license": "MIT", + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.4", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, "engines": { - "node": ">=8" + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" } }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "node_modules/babel-loader/node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", "dev": true, "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" } }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "node_modules/babel-loader/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/array.prototype.findlast": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", - "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "node_modules/babel-loader/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" + "p-locate": "^4.1.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", - "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "node_modules/babel-loader/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-shim-unscopables": "^1.1.0" + "semver": "^6.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/array.prototype.flat": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", - "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "node_modules/babel-loader/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" + "p-try": "^2.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", - "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "node_modules/babel-loader/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" + "p-limit": "^2.2.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/array.prototype.map": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.8.tgz", - "integrity": "sha512-YocPM7bYYu2hXGxWpb5vwZ8cMeudNHYtYBcUDY4Z1GWa53qcnQMWSl25jeBHNzitjl9HW2AWW4ro/S/nftUaOQ==", + "node_modules/babel-loader/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", - "es-array-method-boxes-properly": "^1.0.0", - "es-object-atoms": "^1.0.0", - "is-string": "^1.1.1" + "find-up": "^4.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/array.prototype.reduce": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.8.tgz", - "integrity": "sha512-DwuEqgXFBwbmZSRqt3BpQigWNUoqw9Ml2dTWdF3B2zQlQX4OeUE0zyuzX0fX0IbTvjdkZbcBTU3idgpO78qkTw==", + "node_modules/babel-loader/node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-array-method-boxes-properly": "^1.0.0", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "is-string": "^1.1.1" + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" }, "engines": { - "node": ">= 0.4" + "node": ">= 8.9.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", - "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "node_modules/babel-plugin-add-react-displayname": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.5.tgz", + "integrity": "sha512-LY3+Y0XVDYcShHHorshrDbt4KFWL4bSeniCtl4SYZbask+Syngk1uMPCeN9+nSiZo6zX5s0RTq/J9Pnaaf/KHw==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } + "license": "MIT" }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "node_modules/babel-plugin-apply-mdx-type-prop": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz", + "integrity": "sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==", "dev": true, "license": "MIT", "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" + "@babel/helper-plugin-utils": "7.10.4", + "@mdx-js/util": "1.6.22" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@babel/core": "^7.11.6" } }, - "node_modules/arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "node_modules/babel-plugin-apply-mdx-type-prop/node_modules/@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", "dev": true, + "license": "MIT" + }, + "node_modules/babel-plugin-emotion": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz", + "integrity": "sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA==", "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/serialize": "^0.11.16", + "babel-plugin-macros": "^2.0.0", + "babel-plugin-syntax-jsx": "^6.18.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^1.0.5", + "find-root": "^1.1.0", + "source-map": "^0.5.7" } }, - "node_modules/asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "dev": true, + "node_modules/babel-plugin-emotion/node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", + "license": "MIT" + }, + "node_modules/babel-plugin-emotion/node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "license": "MIT" + }, + "node_modules/babel-plugin-emotion/node_modules/@emotion/serialize": { + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", + "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", "license": "MIT", "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/unitless": "0.7.5", + "@emotion/utils": "0.11.3", + "csstype": "^2.5.7" } }, - "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", - "dev": true, + "node_modules/babel-plugin-emotion/node_modules/@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", "license": "MIT" }, - "node_modules/assert": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.1.tgz", - "integrity": "sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==", - "dev": true, + "node_modules/babel-plugin-emotion/node_modules/@emotion/utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", + "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==", + "license": "MIT" + }, + "node_modules/babel-plugin-emotion/node_modules/babel-plugin-macros": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", + "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", "license": "MIT", "dependencies": { - "object.assign": "^4.1.4", - "util": "^0.10.4" + "@babel/runtime": "^7.7.2", + "cosmiconfig": "^6.0.0", + "resolve": "^1.12.0" } }, - "node_modules/assert/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true, - "license": "ISC" + "node_modules/babel-plugin-emotion/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" }, - "node_modules/assert/node_modules/util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "dev": true, + "node_modules/babel-plugin-emotion/node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", "license": "MIT", "dependencies": { - "inherits": "2.0.3" + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-emotion/node_modules/csstype": { + "version": "2.6.21", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", + "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==", + "license": "MIT" + }, + "node_modules/babel-plugin-emotion/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" } }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-emotion/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", "engines": { - "node": ">=0.10.0" + "node": ">= 6" } }, - "node_modules/ast-types": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", - "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "node_modules/babel-plugin-extract-import-names": { + "version": "1.6.22", + "resolved": "https://registry.npmjs.org/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz", + "integrity": "sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==", "dev": true, "license": "MIT", "dependencies": { - "tslib": "^2.0.1" + "@babel/helper-plugin-utils": "7.10.4" }, - "engines": { - "node": ">=4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/async-each": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", - "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", + "node_modules/babel-plugin-extract-import-names/node_modules/@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", - "optional": true + "license": "MIT" }, - "node_modules/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", - "dev": true, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, "engines": { - "node": ">= 0.4" + "node": ">=10", + "npm": ">=6" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.13.tgz", + "integrity": "sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==", "dev": true, - "license": "ISC", - "engines": { - "node": ">= 4.0.0" + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.4", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.1.7.tgz", + "integrity": "sha512-u+gbS9bbPhZWEeyy1oR/YaaSpod/KDT07arZHb80aTpl8H5ZBq+uN1nN9/xtX7jQyfLdPfoqI4Rue/MQSWJquw==", "dev": true, - "license": "(MIT OR Apache-2.0)", - "bin": { - "atob": "bin/atob.js" + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.1.5", + "core-js-compat": "^3.8.1" }, - "engines": { - "node": ">= 4.5.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/autoprefixer": { - "version": "9.8.8", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.8.tgz", - "integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==", + "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.1.5.tgz", + "integrity": "sha512-nXuzCSwlJ/WKr8qxzW816gwyT6VZgiJG17zR40fou70yfAcqjoNyTLl/DQ+FExw5Hx5KNqshmN8Ldl/r2N7cTg==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.12.0", - "caniuse-lite": "^1.0.30001109", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "picocolors": "^0.2.1", - "postcss": "^7.0.32", - "postcss-value-parser": "^4.1.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" }, - "funding": { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" + "peerDependencies": { + "@babel/core": "^7.4.0-0" } }, - "node_modules/autoprefixer/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true, - "license": "ISC" - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.4.tgz", + "integrity": "sha512-7gD3pRadPrbjhjLyxebmx/WrFYcuSjZ0XbdUujQMZ/fcE9oeewk2U/7PCvez84UeuK3oSjmPZ0Ch0dlupQvGzw==", "dev": true, "license": "MIT", "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "@babel/helper-define-polyfill-provider": "^0.6.4" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/axios": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.28.1.tgz", - "integrity": "sha512-iUcGA5a7p0mVb4Gm/sy+FSECNkPFT4y7wt6OM/CDpO/OnNCvSs3PoMG8ibrC9jRoGYU0gUK5pXVC4NPXq6lHRQ==", + "node_modules/babel-plugin-react-docgen": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.2.1.tgz", + "integrity": "sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ==", + "dev": true, "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" + "ast-types": "^0.14.2", + "lodash": "^4.17.15", + "react-docgen": "^5.0.0" } }, - "node_modules/babel-loader": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.4.1.tgz", - "integrity": "sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==", + "node_modules/babel-plugin-syntax-jsx": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "integrity": "sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==", + "license": "MIT" + }, + "node_modules/bail": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", + "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "license": "MIT", "dependencies": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^2.0.4", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" }, "engines": { - "node": ">= 8.9" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "webpack": ">=2" + "node": ">=0.10.0" } }, - "node_modules/babel-loader/node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "license": "MIT", "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" + "is-descriptor": "^1.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + "node": ">=0.10.0" } }, - "node_modules/babel-loader/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bcp-47-match": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz", + "integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==", "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/babel-loader/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/better-opn": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-2.1.1.tgz", + "integrity": "sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^4.1.0" + "open": "^7.0.3" }, "engines": { - "node": ">=8" + "node": ">8.0.0" } }, - "node_modules/babel-loader/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "node_modules/better-opn/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", "dev": true, "license": "MIT", "dependencies": { - "semver": "^6.0.0" + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" }, "engines": { "node": ">=8" @@ -9024,592 +10163,528 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/babel-loader/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, + "node_modules/bezier-easing": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz", + "integrity": "sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig==", + "license": "MIT" + }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "license": "Unlicense", "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.6" } }, - "node_modules/babel-loader/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true, "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, "engines": { - "node": ">=8" + "node": "*" } }, - "node_modules/babel-loader/node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/babel-loader/node_modules/schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "file-uri-to-path": "1.0.0" } }, - "node_modules/babel-plugin-add-react-displayname": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.5.tgz", - "integrity": "sha512-LY3+Y0XVDYcShHHorshrDbt4KFWL4bSeniCtl4SYZbask+Syngk1uMPCeN9+nSiZo6zX5s0RTq/J9Pnaaf/KHw==", + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true, "license": "MIT" }, - "node_modules/babel-plugin-apply-mdx-type-prop": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz", - "integrity": "sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==", + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "7.10.4", - "@mdx-js/util": "1.6.22" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, - "peerDependencies": { - "@babel/core": "^7.11.6" + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/babel-plugin-apply-mdx-type-prop/node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT" - }, - "node_modules/babel-plugin-emotion": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz", - "integrity": "sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.0.0", - "@emotion/hash": "0.8.0", - "@emotion/memoize": "0.7.4", - "@emotion/serialize": "^0.11.16", - "babel-plugin-macros": "^2.0.0", - "babel-plugin-syntax-jsx": "^6.18.0", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^1.0.5", - "find-root": "^1.1.0", - "source-map": "^0.5.7" + "ms": "2.0.0" } }, - "node_modules/babel-plugin-emotion/node_modules/@emotion/hash": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", - "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", - "license": "MIT" - }, - "node_modules/babel-plugin-emotion/node_modules/@emotion/memoize": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", - "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, "license": "MIT" }, - "node_modules/babel-plugin-emotion/node_modules/@emotion/serialize": { - "version": "0.11.16", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", - "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", - "license": "MIT", + "node_modules/body-parser/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@emotion/hash": "0.8.0", - "@emotion/memoize": "0.7.4", - "@emotion/unitless": "0.7.5", - "@emotion/utils": "0.11.3", - "csstype": "^2.5.7" + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/babel-plugin-emotion/node_modules/@emotion/unitless": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", - "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", - "license": "MIT" - }, - "node_modules/babel-plugin-emotion/node_modules/@emotion/utils": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", - "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==", - "license": "MIT" + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" }, - "node_modules/babel-plugin-emotion/node_modules/babel-plugin-macros": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", - "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", + "node_modules/bootstrap": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz", + "integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.7.2", - "cosmiconfig": "^6.0.0", - "resolve": "^1.12.0" + "peerDependencies": { + "jquery": "1.9.1 - 3", + "popper.js": "^1.16.1" } }, - "node_modules/babel-plugin-emotion/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "license": "MIT" - }, - "node_modules/babel-plugin-emotion/node_modules/cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, "license": "MIT", "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/babel-plugin-emotion/node_modules/csstype": { - "version": "2.6.21", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", - "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==", - "license": "MIT" - }, - "node_modules/babel-plugin-emotion/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "node_modules/bplist-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.1.1.tgz", + "integrity": "sha512-2AEM0FXy8ZxVLBuqX0hqt1gDwcnz2zygEkQ6zaD5Wko/sB9paUNwlpawrFtKeHUAQUOzjVy9AO4oeonqIHKA9Q==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/babel-plugin-emotion/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "license": "ISC", - "engines": { - "node": ">= 6" + "optional": true, + "dependencies": { + "big-integer": "^1.6.7" } }, - "node_modules/babel-plugin-extract-import-names": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz", - "integrity": "sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==", + "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, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "7.10.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "balanced-match": "^1.0.0" } }, - "node_modules/babel-plugin-extract-import-names/node_modules/@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, - "license": "MIT" - }, - "node_modules/babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" + "fill-range": "^7.1.1" }, "engines": { - "node": ">=10", - "npm": ">=6" + "node": ">=8" } }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.13.tgz", - "integrity": "sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==", + "node_modules/broadcast-channel": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/broadcast-channel/-/broadcast-channel-3.7.0.tgz", + "integrity": "sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "detect-node": "^2.1.0", + "js-sha3": "0.8.0", + "microseconds": "0.2.0", + "nano-time": "1.0.0", + "oblivious-set": "1.0.0", + "rimraf": "3.0.2", + "unload": "2.2.0" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.4", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.1.7.tgz", - "integrity": "sha512-u+gbS9bbPhZWEeyy1oR/YaaSpod/KDT07arZHb80aTpl8H5ZBq+uN1nN9/xtX7jQyfLdPfoqI4Rue/MQSWJquw==", + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.1.5", - "core-js-compat": "^3.8.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" } }, - "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.1.5.tgz", - "integrity": "sha512-nXuzCSwlJ/WKr8qxzW816gwyT6VZgiJG17zR40fou70yfAcqjoNyTLl/DQ+FExw5Hx5KNqshmN8Ldl/r2N7cTg==", + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0-0" + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.4.tgz", - "integrity": "sha512-7gD3pRadPrbjhjLyxebmx/WrFYcuSjZ0XbdUujQMZ/fcE9oeewk2U/7PCvez84UeuK3oSjmPZ0Ch0dlupQvGzw==", + "node_modules/browserify-rsa": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.4" + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "engines": { + "node": ">= 0.10" } }, - "node_modules/babel-plugin-react-docgen": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.2.1.tgz", - "integrity": "sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ==", + "node_modules/browserify-sign": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", + "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ast-types": "^0.14.2", - "lodash": "^4.17.15", - "react-docgen": "^5.0.0" + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.5", + "hash-base": "~3.0", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.7", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" } }, - "node_modules/babel-plugin-syntax-jsx": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", - "integrity": "sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==", + "node_modules/browserify-sign/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, "license": "MIT" }, - "node_modules/bail": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", - "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==", + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "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==", + "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, "license": "MIT" }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "node_modules/browserify-sign/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" + "safe-buffer": "~5.1.0" } }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, "license": "MIT", "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" + "pako": "~1.0.5" } }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "node_modules/browserslist": { + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", "dev": true, "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/feross" + "type": "opencollective", + "url": "https://opencollective.com/browserslist" }, { - "type": "patreon", - "url": "https://www.patreon.com/feross" + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" }, { - "type": "consulting", - "url": "https://feross.org/support" + "type": "github", + "url": "https://github.com/sponsors/ai" } ], - "license": "MIT" - }, - "node_modules/bcp-47-match": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz", - "integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/better-opn": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-2.1.1.tgz", - "integrity": "sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==", - "dev": true, - "license": "MIT", - "dependencies": { - "open": "^7.0.3" - }, - "engines": { - "node": ">8.0.0" - } - }, - "node_modules/better-opn/node_modules/open": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", - "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", - "dev": true, "license": "MIT", "dependencies": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" }, - "engines": { - "node": ">=8" + "bin": { + "browserslist": "cli.js" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/big-integer": { - "version": "1.6.52", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", - "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", - "license": "Unlicense", "engines": { - "node": ">=0.6" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "dev": true, "license": "MIT", - "engines": { - "node": "*" + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "file-uri-to-path": "1.0.0" - } + "license": "MIT" }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "node_modules/buffer/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, "license": "MIT" }, - "node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", "dev": true, "license": "MIT" }, - "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c8": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-7.14.0.tgz", + "integrity": "sha512-i04rtkkcNcCf7zsQcSv/T9EbUn4RXQ6mropeMcjFOsQXQ0iGLAr/xT6TImQg4+U9hmNpN9XdvPkjUL1IzbgxJw==", + "dev": true, + "license": "ISC", "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^2.0.0", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-reports": "^3.1.4", + "rimraf": "^3.0.2", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9" + }, + "bin": { + "c8": "bin/c8.js" }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=10.12.0" } }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ms": "2.0.0" + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" } }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "node_modules/cacache/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, - "license": "BSD-3-Clause", + "license": "ISC", "dependencies": { - "side-channel": "^1.0.6" + "yallist": "^4.0.0" }, "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "license": "ISC" - }, - "node_modules/bootstrap": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz", - "integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/twbs" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/bootstrap" - } - ], - "license": "MIT", - "peerDependencies": { - "jquery": "1.9.1 - 3", - "popper.js": "^1.16.1" + "node": ">=10" } }, - "node_modules/boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "node_modules/cacache/node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" + "aggregate-error": "^3.0.0" }, "engines": { "node": ">=10" @@ -9618,201 +10693,171 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bplist-parser": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.1.1.tgz", - "integrity": "sha512-2AEM0FXy8ZxVLBuqX0hqt1gDwcnz2zygEkQ6zaD5Wko/sB9paUNwlpawrFtKeHUAQUOzjVy9AO4oeonqIHKA9Q==", + "node_modules/cacache/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, - "license": "MIT", - "optional": true, - "dependencies": { - "big-integer": "^1.6.7" - } + "license": "ISC" }, - "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==", + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, "license": "MIT", "dependencies": { - "fill-range": "^7.1.1" + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" }, "engines": { - "node": ">=8" - } - }, - "node_modules/broadcast-channel": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/broadcast-channel/-/broadcast-channel-3.7.0.tgz", - "integrity": "sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.7.2", - "detect-node": "^2.1.0", - "js-sha3": "0.8.0", - "microseconds": "0.2.0", - "nano-time": "1.0.0", - "oblivious-set": "1.0.0", - "rimraf": "3.0.2", - "unload": "2.2.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true, - "license": "MIT" - }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dev": true, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/browserify-des": { + "node_modules/call-me-maybe": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", "dev": true, - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } + "license": "MIT" }, - "node_modules/browserify-rsa": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", - "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", - "dev": true, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "license": "MIT", - "dependencies": { - "bn.js": "^5.2.1", - "randombytes": "^2.1.0", - "safe-buffer": "^5.2.1" - }, "engines": { - "node": ">= 0.10" + "node": ">=6" } }, - "node_modules/browserify-sign": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", - "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "bn.js": "^5.2.1", - "browserify-rsa": "^4.1.0", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.5", - "hash-base": "~3.0", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.7", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.12" + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" } }, - "node_modules/browserify-sign/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/browserify-sign/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">= 6" + } }, - "node_modules/browserify-sign/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha512-bA/Z/DERHKqoEOrp+qeGKw1QlvEQkGZSc0XaY6VnTxZr+Kv1G5zFwttpjv8qxZ/sBPT4nthwZaAcsAZTJlSKXQ==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "safe-buffer": "~5.1.0" + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "dev": true, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", "license": "MIT", - "dependencies": { - "pako": "~1.0.5" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "node_modules/caniuse-lite": { + "version": "1.0.30001715", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001715.tgz", + "integrity": "sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==", "dev": true, "funding": [ { @@ -9821,1824 +10866,1905 @@ }, { "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" }, { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "CC-BY-4.0" + }, + "node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "dev": true, "license": "MIT", - "dependencies": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" - }, - "bin": { - "browserslist": "cli.js" - }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "node": ">=4" } }, - "node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "dev": true, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", "license": "MIT", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "dev": true, - "license": "MIT" + "node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "node_modules/buffer/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "node_modules/builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", - "dev": true, - "license": "MIT" + "node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, + "node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", "license": "MIT", - "engines": { - "node": ">= 0.8" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/c8": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/c8/-/c8-7.14.0.tgz", - "integrity": "sha512-i04rtkkcNcCf7zsQcSv/T9EbUn4RXQ6mropeMcjFOsQXQ0iGLAr/xT6TImQg4+U9hmNpN9XdvPkjUL1IzbgxJw==", + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@istanbuljs/schema": "^0.1.3", - "find-up": "^5.0.0", - "foreground-child": "^2.0.0", - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-reports": "^3.1.4", - "rimraf": "^3.0.2", - "test-exclude": "^6.0.0", - "v8-to-istanbul": "^9.0.0", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9" - }, - "bin": { - "c8": "bin/c8.js" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">=10.12.0" + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "license": "ISC", - "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" + "dependencies": { + "is-glob": "^4.0.1" }, "engines": { - "node": ">= 10" + "node": ">= 6" } }, - "node_modules/cacache/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==", + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true, "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, "engines": { "node": ">=10" } }, - "node_modules/cacache/node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "dev": true, "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6.0" } }, - "node_modules/cacache/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/cipher-base": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", + "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", "dev": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "license": "MIT", "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" + "is-descriptor": "^0.1.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { "node": ">= 0.4" } }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, + "node_modules/clean-css": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", + "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", + "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" + "source-map": "~0.6.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 4.0" } }, - "node_modules/call-me-maybe": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "license": "MIT" - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "license": "MIT", + "license": "BSD-3-Clause", "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true, "license": "MIT", - "dependencies": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" + "engines": { + "node": ">=6" } }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", "dev": true, "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, "engines": { - "node": ">= 6" + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" } }, - "node_modules/camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha512-bA/Z/DERHKqoEOrp+qeGKw1QlvEQkGZSc0XaY6VnTxZr+Kv1G5zFwttpjv8qxZ/sBPT4nthwZaAcsAZTJlSKXQ==", + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, - "license": "MIT", - "optional": true, + "license": "ISC", "dependencies": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "node_modules/camelcase-keys/node_modules/camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==", + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, "license": "MIT", - "optional": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001715", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001715.tgz", - "integrity": "sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/case-sensitive-paths-webpack-plugin": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", - "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", - "dev": true, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", "license": "MIT", "engines": { - "node": ">=4" + "node": ">=6" } }, - "node_modules/ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "node_modules/collapse-white-space": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", + "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==", + "dev": true, "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" }, "engines": { - "node": ">=10" + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "engines": { + "node": ">=7.0.0" } }, - "node_modules/character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/color-util": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/color-util/-/color-util-2.2.3.tgz", + "integrity": "sha512-rJyFuTnQsBXQVtY+MXs/sd0K2au9ZlkNB22a48FQcGp40g43eDs7ilbLf/NEm4ph4UxqmkDlwU0G8nl8hEHWJg==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "node_modules/character-entities-html4": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", - "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "engines": { + "node": ">= 6" } }, - "node_modules/character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, "license": "MIT", "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "mime-db": ">= 1.43.0 < 2" }, "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "node": ">= 0.6" } }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/compression": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", + "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" }, "engines": { - "node": ">= 6" + "node": ">= 0.8.0" } }, - "node_modules/chownr": { + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "node_modules/concat-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=6.0" + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/cipher-base": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", - "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", + "node_modules/concat-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" + "safe-buffer": "~5.1.0" } }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", "dev": true, - "license": "MIT", - "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, "license": "MIT", "dependencies": { - "is-descriptor": "^0.1.0" + "safe-buffer": "5.2.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/class-utils/node_modules/is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, "engines": { - "node": ">= 0.4" + "node": ">= 0.6" } }, - "node_modules/classnames": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, "license": "MIT" }, - "node_modules/clean-css": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", - "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, "license": "MIT", - "dependencies": { - "source-map": "~0.6.0" - }, "engines": { - "node": ">= 4.0" + "node": ">= 0.6" } }, - "node_modules/clean-css/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "node_modules/copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "deprecated": "This package is no longer supported.", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" + "license": "ISC", + "dependencies": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" } }, - "node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "node_modules/copy-concurrently/node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "ISC" }, - "node_modules/cli-table3": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", - "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "node_modules/copy-concurrently/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" + "minimist": "^1.2.6" }, - "optionalDependencies": { - "@colors/colors": "1.5.0" + "bin": { + "mkdirp": "bin/cmd.js" } }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "node_modules/copy-concurrently/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" } }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", "dev": true, "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "node_modules/copy-to-clipboard": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "toggle-selection": "^1.0.6" } }, - "node_modules/collapse-white-space": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", - "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==", - "dev": true, + "node_modules/core-js": { + "version": "3.41.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.41.0.tgz", + "integrity": "sha512-SJ4/EHwS36QMJd6h/Rg+GyR4A5xE0FSI3eZ+iBVpfqf1x0eTSg1smWLHrA+2jQThZSh97fmSgFSU8B61nxosxA==", + "hasInstallScript": true, "license": "MIT", "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "node_modules/core-js-compat": { + "version": "3.41.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz", + "integrity": "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==", "dev": true, "license": "MIT", "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "browserslist": "^4.24.4" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/core-js-pure": { + "version": "3.41.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.41.0.tgz", + "integrity": "sha512-71Gzp96T9YPk63aUvE5Q5qP+DryB4ZloUZPSOebGM88VNw8VNfvdA7z6kGA8iGOTEzAomsRidp4jXSmUIJsL+Q==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true, - "license": "ISC", - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/color-util": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/color-util/-/color-util-2.2.3.tgz", - "integrity": "sha512-rJyFuTnQsBXQVtY+MXs/sd0K2au9ZlkNB22a48FQcGp40g43eDs7ilbLf/NEm4ph4UxqmkDlwU0G8nl8hEHWJg==", "license": "MIT" }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "license": "MIT", "dependencies": { - "delayed-stream": "~1.0.0" + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" }, "engines": { - "node": ">= 0.8" + "node": ">=10" } }, - "node_modules/comma-separated-tokens": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", - "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" } }, - "node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "node_modules/cp-file": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-7.0.0.tgz", + "integrity": "sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==", "dev": true, "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "nested-error-stacks": "^2.0.0", + "p-event": "^4.1.0" + }, "engines": { - "node": ">= 6" + "node": ">=8" } }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true, - "license": "MIT" - }, - "node_modules/component-emitter": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", - "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "node_modules/cp-file/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "node_modules/cpy": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/cpy/-/cpy-8.1.2.tgz", + "integrity": "sha512-dmC4mUesv0OYH2kNFEidtf/skUwv4zePmGeepjyyJ0qTo5+8KhA1o99oIAwVVLzQMAeDJml74d6wPPKb6EZUTg==", "dev": true, "license": "MIT", "dependencies": { - "mime-db": ">= 1.43.0 < 2" + "arrify": "^2.0.1", + "cp-file": "^7.0.0", + "globby": "^9.2.0", + "has-glob": "^1.0.0", + "junk": "^3.1.0", + "nested-error-stacks": "^2.1.0", + "p-all": "^2.1.0", + "p-filter": "^2.1.0", + "p-map": "^3.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/compression": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", - "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", + "node_modules/cpy/node_modules/@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", "dev": true, "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "compressible": "~2.0.18", - "debug": "2.6.9", - "negotiator": "~0.6.4", - "on-headers": "~1.0.2", - "safe-buffer": "5.2.1", - "vary": "~1.1.2" - }, "engines": { - "node": ">= 0.8.0" + "node": ">= 6" } }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/cpy/node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "@types/minimatch": "*", + "@types/node": "*" } }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "node_modules/cpy/node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", "dev": true, - "engines": [ - "node >= 0.8" - ], "license": "MIT", "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/concat-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/cpy/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/concat-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/cpy/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", - "dev": true - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "node_modules/cpy/node_modules/dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "5.2.1" + "path-type": "^3.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">=4" } }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "node_modules/cpy/node_modules/fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", "dev": true, "license": "MIT", + "dependencies": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + }, "engines": { - "node": ">= 0.6" + "node": ">=4.0.0" } }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "node_modules/cpy/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", "dev": true, "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "node_modules/cpy/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "deprecated": "This package is no longer supported.", + "node_modules/cpy/node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", "dev": true, "license": "ISC", "dependencies": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" } }, - "node_modules/copy-concurrently/node_modules/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true, - "license": "ISC" - }, - "node_modules/copy-concurrently/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "node_modules/cpy/node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "license": "MIT", "dependencies": { - "minimist": "^1.2.6" + "is-extglob": "^2.1.0" }, - "bin": { - "mkdirp": "bin/cmd.js" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/copy-concurrently/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "node_modules/cpy/node_modules/globby": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", + "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "glob": "^7.1.3" + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.2", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">=6" } }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", + "node_modules/cpy/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 4" } }, - "node_modules/copy-to-clipboard": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", - "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "node_modules/cpy/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/cpy/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, "license": "MIT", - "dependencies": { - "toggle-selection": "^1.0.6" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/core-js": { - "version": "3.41.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.41.0.tgz", - "integrity": "sha512-SJ4/EHwS36QMJd6h/Rg+GyR4A5xE0FSI3eZ+iBVpfqf1x0eTSg1smWLHrA+2jQThZSh97fmSgFSU8B61nxosxA==", - "hasInstallScript": true, + "node_modules/cpy/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/core-js-compat": { - "version": "3.41.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz", - "integrity": "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==", + "node_modules/cpy/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.24.4" + "is-buffer": "^1.1.5" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/core-js-pure": { - "version": "3.41.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.41.0.tgz", - "integrity": "sha512-71Gzp96T9YPk63aUvE5Q5qP+DryB4ZloUZPSOebGM88VNw8VNfvdA7z6kGA8iGOTEzAomsRidp4jXSmUIJsL+Q==", + "node_modules/cpy/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "node_modules/cpy/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, - "license": "MIT" - }, - "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "license": "MIT", "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" + "pify": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=4" } }, - "node_modules/cosmiconfig/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "license": "ISC", + "node_modules/cpy/node_modules/path-type/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=4" } }, - "node_modules/cp-file": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-7.0.0.tgz", - "integrity": "sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==", + "node_modules/cpy/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "nested-error-stacks": "^2.0.0", - "p-event": "^4.1.0" - }, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/cp-file/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "node_modules/cpy/node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true, "license": "MIT", - "dependencies": { - "semver": "^6.0.0" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, - "node_modules/cpy": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/cpy/-/cpy-8.1.2.tgz", - "integrity": "sha512-dmC4mUesv0OYH2kNFEidtf/skUwv4zePmGeepjyyJ0qTo5+8KhA1o99oIAwVVLzQMAeDJml74d6wPPKb6EZUTg==", + "node_modules/cpy/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "dev": true, "license": "MIT", "dependencies": { - "arrify": "^2.0.1", - "cp-file": "^7.0.0", - "globby": "^9.2.0", - "has-glob": "^1.0.0", - "junk": "^3.1.0", - "nested-error-stacks": "^2.1.0", - "p-all": "^2.1.0", - "p-filter": "^2.1.0", - "p-map": "^3.0.0" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/cpy/node_modules/@nodelib/fs.stat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 6" + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" } }, - "node_modules/cpy/node_modules/@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "license": "MIT", "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" } }, - "node_modules/cpy/node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "license": "MIT", "dependencies": { - "array-uniq": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, - "node_modules/cpy/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, - "node_modules/cpy/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "node_modules/crypto-browserify": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", "dev": true, "license": "MIT", "dependencies": { - "is-extendable": "^0.1.0" + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/cpy/node_modules/dir-glob": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", - "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-loader": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", + "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", "dev": true, "license": "MIT", "dependencies": { - "path-type": "^3.0.0" + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.32", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.2.0", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.1.0", + "schema-utils": "^2.7.0", + "semver": "^6.3.0" }, "engines": { - "node": ">=4" + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/cpy/node_modules/fast-glob": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", - "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "node_modules/css-loader/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/css-loader/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "license": "MIT", "dependencies": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" + "minimist": "^1.2.0" }, - "engines": { - "node": ">=4.0.0" + "bin": { + "json5": "lib/cli.js" } }, - "node_modules/cpy/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "node_modules/css-loader/node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "license": "MIT", "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=4.0.0" } }, - "node_modules/cpy/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "node_modules/css-loader/node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", "dev": true, "license": "MIT", "dependencies": { - "is-extendable": "^0.1.0" + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/cpy/node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dev": true, - "license": "ISC", + "license": "BSD-2-Clause", "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/cpy/node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", - "dev": true, + "node_modules/css-selector-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-1.4.1.tgz", + "integrity": "sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==", + "license": "MIT" + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", "license": "MIT", "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" } }, - "node_modules/cpy/node_modules/globby": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", - "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", - "dev": true, + "node_modules/css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", "license": "MIT", "dependencies": { - "@types/glob": "^7.1.1", - "array-union": "^1.0.2", - "dir-glob": "^2.2.2", - "fast-glob": "^2.2.6", - "glob": "^7.1.3", - "ignore": "^4.0.3", - "pify": "^4.0.1", - "slash": "^2.0.0" - }, - "engines": { - "node": ">=6" + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" } }, - "node_modules/cpy/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "engines": { - "node": ">= 4" + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/cpy/node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", "dev": true, "license": "MIT" }, - "node_modules/cpy/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/cpy/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "kind-of": "^3.0.2" + "array-find-index": "^1.0.1" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/cpy/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "node_modules/cyclist": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.2.tgz", + "integrity": "sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", "dependencies": { - "is-buffer": "^1.1.5" + "internmap": "1 - 2" }, "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "node_modules/cpy/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "license": "MIT", - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "node_modules/cpy/node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "license": "MIT", + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", "dependencies": { - "pify": "^3.0.0" + "delaunator": "5" }, "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/cpy/node_modules/path-type/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "license": "MIT", + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/cpy/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "license": "MIT", + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", "engines": { - "node": ">=6" + "node": ">=12" } }, - "node_modules/cpy/node_modules/slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true, - "license": "MIT", + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, "engines": { - "node": ">=6" + "node": ">=12" } }, - "node_modules/cpy/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "dev": true, - "license": "MIT", + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" } }, - "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", - "dev": true, - "license": "MIT" - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, - "license": "MIT", + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" } }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "d3-time": "1 - 3" }, "engines": { - "node": ">= 8" + "node": ">=12" } }, - "node_modules/crypto-browserify": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", - "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "dev": true, "license": "MIT", "dependencies": { - "browserify-cipher": "^1.0.1", - "browserify-sign": "^4.2.3", - "create-ecdh": "^4.0.4", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "diffie-hellman": "^5.0.3", - "hash-base": "~3.0.4", - "inherits": "^2.0.4", - "pbkdf2": "^3.1.2", - "public-encrypt": "^4.0.3", - "randombytes": "^2.1.0", - "randomfill": "^1.0.4" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" }, "engines": { - "node": ">= 0.10" + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/css-loader": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", - "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "dev": true, "license": "MIT", "dependencies": { - "camelcase": "^5.3.1", - "cssesc": "^3.0.0", - "icss-utils": "^4.1.1", - "loader-utils": "^1.2.3", - "normalize-path": "^3.0.0", - "postcss": "^7.0.32", - "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^3.0.2", - "postcss-modules-scope": "^2.2.0", - "postcss-modules-values": "^3.0.0", - "postcss-value-parser": "^4.1.0", - "schema-utils": "^2.7.0", - "semver": "^6.3.0" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" }, "engines": { - "node": ">= 8.9.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "url": "https://github.com/sponsors/inspect-js" } }, - "node_modules/css-loader/node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, "engines": { - "node": ">=6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/css-loader/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", "license": "MIT", "dependencies": { - "minimist": "^1.2.0" + "@babel/runtime": "^7.21.0" }, - "bin": { - "json5": "lib/cli.js" + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" } }, - "node_modules/css-loader/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", - "dev": true, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "ms": "^2.1.3" }, "engines": { - "node": ">=4.0.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/css-loader/node_modules/schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - }, + "optional": true, "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": ">=0.10.0" } }, - "node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, + "node_modules/decode-named-character-reference": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz", + "integrity": "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==", + "license": "MIT", "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" + "character-entities": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/fb55" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/css-selector-parser": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-1.4.1.tgz", - "integrity": "sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==", - "license": "MIT" - }, - "node_modules/css-vendor": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", - "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "node_modules/decode-named-character-reference/node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.8.3", - "is-in-browser": "^1.0.2" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "node": ">=0.10" } }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "node_modules/default-browser-id": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-1.0.4.tgz", + "integrity": "sha512-qPy925qewwul9Hifs+3sx1ZYn14obHxpkX+mPD369w4Rzg+YkJBgi3SOvwUq81nWSjqGUegIgEPwD8u+HUnxlw==", "dev": true, "license": "MIT", + "optional": true, + "dependencies": { + "bplist-parser": "^0.1.0", + "meow": "^3.1.0", + "untildify": "^2.0.0" + }, "bin": { - "cssesc": "bin/cssesc" + "default-browser-id": "cli.js" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT" - }, - "node_modules/currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==", + "node_modules/default-browser-id/node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "array-find-index": "^1.0.1" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/cyclist": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.2.tgz", - "integrity": "sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA==", + "node_modules/default-browser-id/node_modules/indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha512-aqwDFWSgSgfRaEwao5lg5KEcVd/2a+D1rvoG7NdilmYz0NwRk6StWpWdz/Hpk34MKPpx7s8XxUqimfcQK6gGlg==", "dev": true, - "license": "MIT" - }, - "node_modules/d3-array": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", - "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", - "license": "ISC", + "license": "MIT", + "optional": true, "dependencies": { - "internmap": "1 - 2" + "repeating": "^2.0.0" }, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "license": "ISC", + "node_modules/default-browser-id/node_modules/meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + }, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "license": "BSD-3-Clause", + "node_modules/default-browser-id/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/d3-format": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", - "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", - "license": "ISC", + "node_modules/default-browser-id/node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3" - }, + "node_modules/default-browser-id/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "optional": true, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", - "license": "ISC", + "node_modules/default-browser-id/node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "license": "ISC", + "node_modules/default-browser-id/node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" }, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/d3-shape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "license": "ISC", + "node_modules/default-browser-id/node_modules/redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g==", + "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "d3-path": "^3.1.0" + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" }, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/d3-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "license": "ISC", + "node_modules/default-browser-id/node_modules/strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA==", + "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "d3-array": "2 - 3" + "get-stdin": "^4.0.1" + }, + "bin": { + "strip-indent": "cli.js" }, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "license": "ISC", + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", "dependencies": { - "d3-time": "1 - 3" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { - "node": ">=12" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "license": "ISC", + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" @@ -11647,2016 +12773,2031 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" + "node": ">=0.10.0" } }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.8" } }, - "node_modules/date-fns": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.21.0" - }, + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.11" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detab": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.4.tgz", + "integrity": "sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "repeat-string": "^1.5.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/dayjs": { - "version": "1.11.13", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", - "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "license": "MIT" }, - "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "node_modules/detect-package-manager": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-package-manager/-/detect-package-manager-2.0.1.tgz", + "integrity": "sha512-j/lJHyoLlWi6G1LDdLgvUtz60Zo5GEj+sVYtTVXnYLDPuzgC3llMxonXym9zIwhhUII8vjdw0LXxavpLqTbl1A==", + "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.3" + "execa": "^5.1.1" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=12" } }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "node_modules/detect-port": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.6.1.tgz", + "integrity": "sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q==", "dev": true, "license": "MIT", - "optional": true, + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 4.0.0" } }, - "node_modules/decimal.js-light": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", - "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", - "license": "MIT" - }, - "node_modules/decode-named-character-reference": { + "node_modules/devlop": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz", - "integrity": "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", "license": "MIT", "dependencies": { - "character-entities": "^2.0.0" + "dequal": "^2.0.0" }, "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/decode-named-character-reference/node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" } }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "node_modules/diff-sequences": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", + "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10" + "node": ">= 6" } }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", "dev": true, "license": "MIT" }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-browser-id": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-1.0.4.tgz", - "integrity": "sha512-qPy925qewwul9Hifs+3sx1ZYn14obHxpkX+mPD369w4Rzg+YkJBgi3SOvwUq81nWSjqGUegIgEPwD8u+HUnxlw==", + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "bplist-parser": "^0.1.0", - "meow": "^3.1.0", - "untildify": "^2.0.0" - }, - "bin": { - "default-browser-id": "cli.js" + "path-type": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/default-browser-id/node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", - "dev": true, + "node_modules/direction": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/direction/-/direction-2.0.1.tgz", + "integrity": "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==", "license": "MIT", - "optional": true, - "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "bin": { + "direction": "cli.js" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/default-browser-id/node_modules/indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha512-aqwDFWSgSgfRaEwao5lg5KEcVd/2a+D1rvoG7NdilmYz0NwRk6StWpWdz/Hpk34MKPpx7s8XxUqimfcQK6gGlg==", + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, - "license": "MIT", - "optional": true, + "license": "Apache-2.0", "dependencies": { - "repeating": "^2.0.0" + "esutils": "^2.0.2" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0.0" } }, - "node_modules/default-browser-id/node_modules/meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==", + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" + "utila": "~0.4" } }, - "node_modules/default-browser-id/node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", - "dev": true, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", "license": "MIT", - "optional": true, "dependencies": { - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" } }, - "node_modules/default-browser-id/node_modules/path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", - "dev": true, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "license": "MIT", - "optional": true, "dependencies": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/default-browser-id/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" + }, + "node_modules/domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", "dev": true, "license": "MIT", - "optional": true, "engines": { - "node": ">=0.10.0" + "node": ">=0.4", + "npm": ">=1.2" } }, - "node_modules/default-browser-id/node_modules/read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", - "dev": true, - "license": "MIT", - "optional": true, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "license": "BSD-2-Clause", "dependencies": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" + "domelementtype": "^2.2.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/default-browser-id/node_modules/read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", - "dev": true, - "license": "MIT", - "optional": true, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "license": "BSD-2-Clause", "dependencies": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/default-browser-id/node_modules/redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g==", + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" - }, + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "license": "BSD-2-Clause", "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/default-browser-id/node_modules/strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA==", + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", - "optional": true, "dependencies": { - "get-stdin": "^4.0.1" - }, - "bin": { - "strip-indent": "cli.js" + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", "dev": true, "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" } }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "node_modules/duplexify/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/duplexify/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "node_modules/duplexify/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/duplexify/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "safe-buffer": "~5.1.0" } }, - "node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.139", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.139.tgz", + "integrity": "sha512-GGnRYOTdN5LYpwbIr0rwP/ZHOQSvAF6TG0LSzp28uCBb9JiXHJGmaaKw29qjNJc5bGnnp6kXJqRnGMQoELwi5w==", + "dev": true, + "license": "ISC" + }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", "dev": true, "license": "MIT", "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "dev": true, + "license": "MIT" }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT" }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">= 4" } }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 0.8" } }, - "node_modules/des.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", - "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", - "dev": true, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "license": "MIT", "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "iconv-lite": "^0.6.2" } }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=0.10.0" } }, - "node_modules/detab": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.4.tgz", - "integrity": "sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==", + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "license": "MIT", "dependencies": { - "repeat-string": "^1.5.4" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "once": "^1.4.0" } }, - "node_modules/detect-node": { + "node_modules/endent": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "license": "MIT" - }, - "node_modules/detect-package-manager": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-package-manager/-/detect-package-manager-2.0.1.tgz", - "integrity": "sha512-j/lJHyoLlWi6G1LDdLgvUtz60Zo5GEj+sVYtTVXnYLDPuzgC3llMxonXym9zIwhhUII8vjdw0LXxavpLqTbl1A==", + "resolved": "https://registry.npmjs.org/endent/-/endent-2.1.0.tgz", + "integrity": "sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==", "dev": true, "license": "MIT", "dependencies": { - "execa": "^5.1.1" - }, - "engines": { - "node": ">=12" + "dedent": "^0.7.0", + "fast-json-parse": "^1.0.3", + "objectorarray": "^1.0.5" } }, - "node_modules/detect-port": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.6.1.tgz", - "integrity": "sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q==", + "node_modules/enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", "dev": true, - "license": "MIT", "dependencies": { - "address": "^1.0.1", - "debug": "4" - }, - "bin": { - "detect": "bin/detect-port.js", - "detect-port": "bin/detect-port.js" + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" }, "engines": { - "node": ">= 4.0.0" + "node": ">=6.9.0" } }, - "node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } + "node_modules/enhanced-resolve/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" }, - "node_modules/diff-sequences": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", - "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", + "node_modules/enhanced-resolve/node_modules/memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", "dev": true, "license": "MIT", + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + }, "engines": { - "node": ">= 6" + "node": ">=4.3.0 <5.0.0 || >=5.10" } }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "node_modules/enhanced-resolve/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "node_modules/enhanced-resolve/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, "license": "MIT" }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/direction": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/direction/-/direction-2.0.1.tgz", - "integrity": "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==", - "license": "MIT", - "bin": { - "direction": "cli.js" - }, + "node_modules/enhanced-resolve/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "license": "BSD-2-Clause", "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "esutils": "^2.0.2" + "prr": "~1.0.1" }, - "engines": { - "node": ">=6.0.0" + "bin": { + "errno": "cli.js" } }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true, - "license": "MIT" - }, - "node_modules/dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dev": true, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "license": "MIT", "dependencies": { - "utila": "~0.4" + "is-arrayish": "^0.2.1" } }, - "node_modules/dom-helpers": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" + "stackframe": "^1.3.4" } }, - "node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "node_modules/es-abstract": { + "version": "1.23.9", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", + "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", + "dev": true, "license": "MIT", "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.0", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-regex": "^1.2.1", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.0", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.3", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.18" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/dom-walk": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", - "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" - }, - "node_modules/domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", "engines": { - "node": ">=0.4", - "npm": ">=1.2" + "node": ">= 0.4" } }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause" - }, - "node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.2.0" - }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "node": ">= 0.4" } }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "license": "BSD-2-Clause", + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "license": "MIT", "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" }, "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "node_modules/es-iterator-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", "dev": true, "license": "MIT", "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "license": "BSD-2-Clause", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.6", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.4", + "safe-array-concat": "^1.1.3" + }, "engines": { - "node": ">=10" + "node": ">= 0.4" } }, - "node_modules/dotenv-expand": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", - "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" + "es-errors": "^1.3.0" }, "engines": { "node": ">= 0.4" } }, - "node_modules/duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "dev": true, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "license": "MIT", "dependencies": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/duplexify/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/duplexify/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", "dev": true, "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/duplexify/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/duplexify/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.139", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.139.tgz", - "integrity": "sha512-GGnRYOTdN5LYpwbIr0rwP/ZHOQSvAF6TG0LSzp28uCBb9JiXHJGmaaKw29qjNJc5bGnnp6kXJqRnGMQoELwi5w==", - "dev": true, - "license": "ISC" - }, - "node_modules/elliptic": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "node_modules/es5-shim": { + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.6.7.tgz", + "integrity": "sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ==", "dev": true, "license": "MIT", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" + "engines": { + "node": ">=0.4.0" } }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", - "dev": true, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", "license": "MIT" }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "node_modules/es6-shim": { + "version": "0.35.8", + "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.8.tgz", + "integrity": "sha512-Twf7I2v4/1tLoIXMT8HlqaBSS5H2wQTs2wx3MNYCI8K1R1/clXyCazrcVCPm/FuO9cyV8+leEaZOWD5C253NDg==", "dev": true, "license": "MIT" }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "node_modules/esbuild": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", + "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", "dev": true, + "hasInstallScript": true, "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, "engines": { - "node": ">= 4" + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.2", + "@esbuild/android-arm": "0.25.2", + "@esbuild/android-arm64": "0.25.2", + "@esbuild/android-x64": "0.25.2", + "@esbuild/darwin-arm64": "0.25.2", + "@esbuild/darwin-x64": "0.25.2", + "@esbuild/freebsd-arm64": "0.25.2", + "@esbuild/freebsd-x64": "0.25.2", + "@esbuild/linux-arm": "0.25.2", + "@esbuild/linux-arm64": "0.25.2", + "@esbuild/linux-ia32": "0.25.2", + "@esbuild/linux-loong64": "0.25.2", + "@esbuild/linux-mips64el": "0.25.2", + "@esbuild/linux-ppc64": "0.25.2", + "@esbuild/linux-riscv64": "0.25.2", + "@esbuild/linux-s390x": "0.25.2", + "@esbuild/linux-x64": "0.25.2", + "@esbuild/netbsd-arm64": "0.25.2", + "@esbuild/netbsd-x64": "0.25.2", + "@esbuild/openbsd-arm64": "0.25.2", + "@esbuild/openbsd-x64": "0.25.2", + "@esbuild/sunos-x64": "0.25.2", + "@esbuild/win32-arm64": "0.25.2", + "@esbuild/win32-ia32": "0.25.2", + "@esbuild/win32-x64": "0.25.2" } }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=6" } }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "license": "MIT", - "dependencies": { - "iconv-lite": "^0.6.2" - } + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "once": "^1.4.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/endent": { + "node_modules/escodegen": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/endent/-/endent-2.1.0.tgz", - "integrity": "sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==", - "dev": true, - "license": "MIT", - "dependencies": { - "dedent": "^0.7.0", - "fast-json-parse": "^1.0.3", - "objectorarray": "^1.0.5" - } - }, - "node_modules/enhanced-resolve": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", - "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.5.0", - "tapable": "^1.0.0" + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" }, "engines": { - "node": ">=6.9.0" + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" } }, - "node_modules/enhanced-resolve/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "license": "MIT" + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/enhanced-resolve/node_modules/memory-fs": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", - "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "node_modules/eslint": { + "version": "9.25.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.0.tgz", + "integrity": "sha512-MsBdObhM4cEwkzCiraDv7A6txFXEqtNXOb877TsSp2FCkBNl8JfVQrmiuDqC1IkejT6JLPzYBXx/xAiYhyzgGA==", "dev": true, "license": "MIT", "dependencies": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.13.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.25.0", + "@eslint/plugin-kit": "^0.2.8", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" }, "engines": { - "node": ">=4.3.0 <5.0.0 || >=5.10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "node_modules/enhanced-resolve/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" } }, - "node_modules/enhanced-resolve/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/enhanced-resolve/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "license": "BSD-2-Clause", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "ms": "^2.1.1" } }, - "node_modules/errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "node_modules/eslint-import-resolver-typescript": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.0.tgz", + "integrity": "sha512-aV3/dVsT0/H9BtpNwbaqvl+0xGMRGzncLyhm793NFGvbwGGvzyAykqWZ8oZlZuGwuHkwJjhWJkG1cM3ynvd2pQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "prr": "~1.0.1" + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.12", + "unrs-resolver": "^1.3.2" }, - "bin": { - "errno": "cli.js" + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } } }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "node_modules/eslint-module-utils": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", + "dev": true, "license": "MIT", "dependencies": { - "is-arrayish": "^0.2.1" + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "node_modules/error-stack-parser": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", - "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", "dependencies": { - "stackframe": "^1.3.4" + "ms": "^2.1.1" } }, - "node_modules/es-abstract": { - "version": "1.23.9", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", - "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", + "node_modules/eslint-plugin-import": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", + "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, "license": "MIT", "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.0", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.0", "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-regex": "^1.2.1", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.0", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.3", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.18" + "is-core-module": "^2.15.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.8", + "tsconfig-paths": "^3.15.0" }, "engines": { - "node": ">= 0.4" + "node": ">=4" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, - "node_modules/es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT" - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "ms": "^2.1.1" } }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" + "esutils": "^2.0.2" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/es-iterator-helpers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", - "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.6", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "iterator.prototype": "^1.1.4", - "safe-array-concat": "^1.1.3" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">= 0.4" + "node": "*" } }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0" + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" } }, - "node_modules/es-shim-unscopables": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", - "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "hasown": "^2.0.2" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">= 0.4" + "node": "*" } }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", "dev": true, "license": "MIT", "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, - "engines": { - "node": ">= 0.4" + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es5-shim": { - "version": "4.6.7", - "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.6.7.tgz", - "integrity": "sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "license": "MIT" - }, - "node_modules/es6-shim": { - "version": "0.35.8", - "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.8.tgz", - "integrity": "sha512-Twf7I2v4/1tLoIXMT8HlqaBSS5H2wQTs2wx3MNYCI8K1R1/clXyCazrcVCPm/FuO9cyV8+leEaZOWD5C253NDg==", - "dev": true, - "license": "MIT" - }, - "node_modules/esbuild": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", - "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", + "node_modules/eslint-scope": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.2", - "@esbuild/android-arm": "0.25.2", - "@esbuild/android-arm64": "0.25.2", - "@esbuild/android-x64": "0.25.2", - "@esbuild/darwin-arm64": "0.25.2", - "@esbuild/darwin-x64": "0.25.2", - "@esbuild/freebsd-arm64": "0.25.2", - "@esbuild/freebsd-x64": "0.25.2", - "@esbuild/linux-arm": "0.25.2", - "@esbuild/linux-arm64": "0.25.2", - "@esbuild/linux-ia32": "0.25.2", - "@esbuild/linux-loong64": "0.25.2", - "@esbuild/linux-mips64el": "0.25.2", - "@esbuild/linux-ppc64": "0.25.2", - "@esbuild/linux-riscv64": "0.25.2", - "@esbuild/linux-s390x": "0.25.2", - "@esbuild/linux-x64": "0.25.2", - "@esbuild/netbsd-arm64": "0.25.2", - "@esbuild/netbsd-x64": "0.25.2", - "@esbuild/openbsd-arm64": "0.25.2", - "@esbuild/openbsd-x64": "0.25.2", - "@esbuild/sunos-x64": "0.25.2", - "@esbuild/win32-arm64": "0.25.2", - "@esbuild/win32-ia32": "0.25.2", - "@esbuild/win32-x64": "0.25.2" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "node_modules/eslint/node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true, "license": "MIT" }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "BSD-2-Clause", + "license": "ISC", "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" + "node": "*" } }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, - "license": "BSD-3-Clause", - "optional": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint": { - "version": "9.25.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.0.tgz", - "integrity": "sha512-MsBdObhM4cEwkzCiraDv7A6txFXEqtNXOb877TsSp2FCkBNl8JfVQrmiuDqC1IkejT6JLPzYBXx/xAiYhyzgGA==", + "node_modules/espree/node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "dev": true, "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.20.0", - "@eslint/config-helpers": "^0.2.1", - "@eslint/core": "^0.13.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.25.0", - "@eslint/plugin-kit": "^0.2.8", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.3.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, "bin": { - "eslint": "bin/eslint.js" + "acorn": "bin/acorn" }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } + "engines": { + "node": ">=4" } }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" } }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "ms": "^2.1.1" + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" } }, - "node_modules/eslint-import-resolver-typescript": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.0.tgz", - "integrity": "sha512-aV3/dVsT0/H9BtpNwbaqvl+0xGMRGzncLyhm793NFGvbwGGvzyAykqWZ8oZlZuGwuHkwJjhWJkG1cM3ynvd2pQ==", + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "ISC", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-to-babel": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/estree-to-babel/-/estree-to-babel-3.2.1.tgz", + "integrity": "sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==", + "dev": true, + "license": "MIT", "dependencies": { - "@nolyfill/is-core-module": "1.0.39", - "debug": "^4.4.0", - "get-tsconfig": "^4.10.0", - "is-bun-module": "^2.0.0", - "stable-hash": "^0.0.5", - "tinyglobby": "^0.2.12", - "unrs-resolver": "^1.3.2" + "@babel/traverse": "^7.1.6", + "@babel/types": "^7.2.0", + "c8": "^7.6.0" }, "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-import-resolver-typescript" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*", - "eslint-plugin-import-x": "*" - }, - "peerDependenciesMeta": { - "eslint-plugin-import": { - "optional": true - }, - "eslint-plugin-import-x": { - "optional": true - } + "node": ">=8.3.0" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/eslint-module-utils": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", - "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, "license": "MIT", - "dependencies": { - "debug": "^3.2.7" - }, "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } + "node": ">= 0.6" } }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" } }, - "node_modules/eslint-plugin-import": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", - "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "license": "MIT", "dependencies": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.8", - "array.prototype.findlastindex": "^1.2.5", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.0", - "hasown": "^2.0.2", - "is-core-module": "^2.15.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.0", - "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.8", - "tsconfig-paths": "^3.15.0" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=10" }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "ms": "2.0.0" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "esutils": "^2.0.2" + "is-descriptor": "^0.1.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "is-extendable": "^0.1.0" }, "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-react": { - "version": "7.37.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", - "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, "license": "MIT", "dependencies": { - "array-includes": "^3.1.8", - "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.3", - "array.prototype.tosorted": "^1.1.4", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.2.1", - "estraverse": "^5.3.0", - "hasown": "^2.0.2", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.9", - "object.fromentries": "^2.0.8", - "object.values": "^1.2.1", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.12", - "string.prototype.repeat": "^1.0.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + "node": ">= 0.4" } }, - "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/expand-brackets/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-react/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } + "license": "MIT" }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" }, - "bin": { - "resolve": "bin/resolve" + "engines": { + "node": ">= 0.10.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/eslint-scope": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", - "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "ms": "2.0.0" } }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, - "license": "Apache-2.0", + "license": "MIT" + }, + "node_modules/express/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=0.6" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint/node_modules/@types/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", - "dev": true, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, - "funding": { - "url": "https://opencollective.com/eslint" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "acorn": "^8.14.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" + "is-descriptor": "^1.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=0.10.0" } }, - "node_modules/espree/node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, "license": "MIT", - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "is-extendable": "^0.1.0" }, "engines": { - "node": ">=0.4.0" + "node": ">=0.10.0" } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "node_modules/extglob/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=0.10.0" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz", + "integrity": "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==", + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=6.0.0" } }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "estraverse": "^5.1.0" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" }, "engines": { - "node": ">=0.10" + "node": ">=8.6.0" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "license": "BSD-2-Clause", + "license": "ISC", "dependencies": { - "estraverse": "^5.2.0" + "is-glob": "^4.0.1" }, "engines": { - "node": ">=4.0" + "node": ">= 6" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/fast-json-parse": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", + "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" } }, - "node_modules/estree-to-babel": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/estree-to-babel/-/estree-to-babel-3.2.1.tgz", - "integrity": "sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==", - "dev": true, + "node_modules/fault": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.1.6", - "@babel/types": "^7.2.0", - "c8": "^7.6.0" + "format": "^0.2.0" }, - "engines": { - "node": ">=8.3.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "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/fetch-retry": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/fetch-retry/-/fetch-retry-5.0.6.tgz", + "integrity": "sha512-3yurQZ2hD9VISAhJJP9bpYFNQrHHBXE2JxxjY5aLEcDi46RmAzJE2OC9FAde0yis5ElW0jTTzs0zfg/Cca4XqQ==", "dev": true, "license": "MIT" }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "node_modules/figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", + "deprecated": "This module is no longer supported.", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "license": "MIT" + "license": "ISC" }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, "engines": { - "node": ">=0.8.x" + "node": ">=16.0.0" } }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "node_modules/file-entry-cache/node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" } }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", "dev": true, "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">= 10.13.0" }, "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "node_modules/file-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, "license": "MIT", "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/file-system-cache": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/file-system-cache/-/file-system-cache-1.1.0.tgz", + "integrity": "sha512-IzF5MBq+5CR0jXx5RxPe4BICl/oEhBSXKaL9fLhAXrIfIUS77Hr4vzrYyqYMHN6uTt+BOqi3fDCTjjEBCjERKw==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "fs-extra": "^10.1.0", + "ramda": "^0.28.0" } }, - "node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "node_modules/file-system-cache/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "license": "MIT", "dependencies": { - "is-descriptor": "^0.1.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "dev": true, "license": "MIT", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } + "optional": true }, - "node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">= 0.4" - } - }, - "node_modules/expand-brackets/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, "license": "MIT", "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" + "unpipe": "~1.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "engines": { + "node": ">= 0.8" } }, - "node_modules/express/node_modules/debug": { + "node_modules/finalhandler/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", @@ -13666,534 +14807,552 @@ "ms": "2.0.0" } }, - "node_modules/express/node_modules/ms": { + "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, "license": "MIT" }, - "node_modules/express/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "side-channel": "^1.0.6" + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" }, "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=6" } }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "license": "MIT" - }, - "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "node_modules/find-cache-dir/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "license": "MIT", "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "locate-path": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "node_modules/find-cache-dir/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "license": "MIT", "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "node_modules/find-cache-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", "dependencies": { - "is-descriptor": "^1.0.0" + "p-try": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "node_modules/find-cache-dir/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "license": "MIT", "dependencies": { - "is-extendable": "^0.1.0" + "p-limit": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/extglob/node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "node_modules/find-cache-dir/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-equals": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz", - "integrity": "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==", + "node_modules/find-cache-dir/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, "engines": { - "node": ">=6.0.0" + "node": ">=6" } }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=8.6.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" }, "engines": { - "node": ">= 6" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/fast-json-parse": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", - "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "node_modules/flush-write-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, "license": "MIT" }, - "node_modules/fast-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", - "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "node_modules/flush-write-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fault": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", - "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", "license": "MIT", "dependencies": { - "format": "^0.2.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/fetch-retry": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/fetch-retry/-/fetch-retry-5.0.6.tgz", - "integrity": "sha512-3yurQZ2hD9VISAhJJP9bpYFNQrHHBXE2JxxjY5aLEcDi46RmAzJE2OC9FAde0yis5ElW0jTTzs0zfg/Cca4XqQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/figgy-pudding": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", - "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", - "deprecated": "This module is no longer supported.", + "node_modules/flush-write-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "node_modules/flush-write-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^4.0.0" - }, + "safe-buffer": "~5.1.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", "engines": { - "node": ">=16.0.0" + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, - "node_modules/file-entry-cache/node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, "license": "MIT", "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" + "is-callable": "^1.2.7" }, "engines": { - "node": ">=16" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", "dev": true, "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "license": "ISC", "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" }, "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "node": ">=8.0.0" } }, - "node_modules/file-loader/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", + "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">=10", + "yarn": ">=1.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "vue-template-compiler": "*", + "webpack": ">= 4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } } }, - "node_modules/file-system-cache": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/file-system-cache/-/file-system-cache-1.1.0.tgz", - "integrity": "sha512-IzF5MBq+5CR0jXx5RxPe4BICl/oEhBSXKaL9fLhAXrIfIUS77Hr4vzrYyqYMHN6uTt+BOqi3fDCTjjEBCjERKw==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", "dependencies": { - "fs-extra": "^10.1.0", - "ramda": "^0.28.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/file-system-cache/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", "dev": true, "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" }, "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", - "optional": true + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", "dev": true, "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" }, "engines": { - "node": ">=8" + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">= 0.8" + "node": ">=10" } }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "license": "MIT", "dependencies": { - "ms": "2.0.0" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } }, - "node_modules/find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, "license": "MIT", - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - }, "engines": { - "node": ">=6" + "node": ">= 0.6" } }, - "node_modules/find-cache-dir/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^3.0.0" + "map-cache": "^0.2.2" }, "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/find-cache-dir/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, "license": "MIT", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, "engines": { - "node": ">=6" + "node": ">= 0.6" } }, - "node_modules/find-cache-dir/node_modules/p-limit": { + "node_modules/from2": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", "dev": true, "license": "MIT", "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" } }, - "node_modules/find-cache-dir/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "node_modules/from2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/from2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/find-cache-dir/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "node_modules/from2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } + "license": "MIT" }, - "node_modules/find-cache-dir/node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "node_modules/from2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=6" + "safe-buffer": "~5.1.0" } }, - "node_modules/find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "license": "MIT" - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "minipass": "^3.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">= 8" } }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", "dev": true, - "license": "ISC" + "license": "Unlicense" }, - "node_modules/flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "node_modules/fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==", + "deprecated": "This package is no longer supported.", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" } }, - "node_modules/flush-write-stream/node_modules/isarray": { + "node_modules/fs-write-stream-atomic/node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, "license": "MIT" }, - "node_modules/flush-write-stream/node_modules/readable-stream": { + "node_modules/fs-write-stream-atomic/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", @@ -14209,14 +15368,14 @@ "util-deprecate": "~1.0.1" } }, - "node_modules/flush-write-stream/node_modules/safe-buffer": { + "node_modules/fs-write-stream-atomic/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, "license": "MIT" }, - "node_modules/flush-write-stream/node_modules/string_decoder": { + "node_modules/fs-write-stream-atomic/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", @@ -14226,430 +15385,436 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "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, + "license": "MIT", + "optional": true, + "os": [ + "darwin" ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, "engines": { - "node": ">=4.0" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", "dependencies": { - "is-callable": "^1.2.7" + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10" } }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" } }, - "node_modules/foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - }, "engines": { - "node": ">=8.0.0" + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/fork-ts-checker-webpack-plugin": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", - "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", - "dev": true, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "chokidar": "^3.4.2", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "glob": "^7.1.6", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { - "node": ">=10", - "yarn": ">=1.0.0" - }, - "peerDependencies": { - "eslint": ">= 6", - "typescript": ">= 2.7", - "vue-template-compiler": "*", - "webpack": ">= 4" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - }, - "vue-template-compiler": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "node_modules/get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", "dev": true, "license": "MIT", - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - }, + "optional": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", "engines": { - "node": "*" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" }, "engines": { - "node": ">= 8.9.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "node_modules/get-tsconfig": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", + "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" }, - "engines": { - "node": ">=10" + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", "dev": true, - "license": "ISC", - "engines": { - "node": ">= 6" - } - }, - "node_modules/form-data": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "mime-types": "^2.1.12" - }, "engines": { - "node": ">= 6" + "node": ">=0.10.0" } }, - "node_modules/format": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", - "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", - "engines": { - "node": ">=0.4.x" - } + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "license": "ISC" }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "license": "MIT", + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, "engines": { - "node": ">= 0.6" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "map-cache": "^0.2.2" + "is-glob": "^4.0.3" }, "engines": { - "node": ">=0.10.0" + "node": ">=10.13.0" } }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "node_modules/glob-promise": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/glob-promise/-/glob-promise-3.4.0.tgz", + "integrity": "sha512-q08RJ6O+eJn+dVanerAndJwIcumgbDdYiUT7zFQl3Wm1xD6fBKtah7H8ZJChj4wP+8C+QfeVy8xautR7rdmKEw==", "dev": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "@types/glob": "*" + }, "engines": { - "node": ">= 0.6" + "node": ">=4" + }, + "peerDependencies": { + "glob": "*" } }, - "node_modules/from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "license": "MIT", "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/from2/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } }, - "node_modules/from2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "min-document": "^2.19.0", + "process": "^0.11.10" } }, - "node_modules/from2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/from2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/globals": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz", + "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==", "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, "license": "MIT", "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { - "node": ">=10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "minipass": "^3.0.0" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" }, "engines": { - "node": ">= 8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fs-monkey": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", - "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", "dev": true, - "license": "Unlicense" + "license": "MIT" }, - "node_modules/fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "dependencies": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" + "node_modules/goober": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz", + "integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==", + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" } }, - "node_modules/fs-write-stream-atomic/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/fs-write-stream-atomic/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fs-write-stream-atomic/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true, "license": "MIT" }, - "node_modules/fs-write-stream-atomic/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "license": "BSD-3-Clause", "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" - }, "engines": { "node": ">= 0.4" }, @@ -14657,74 +15822,63 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=8" } }, - "node_modules/gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "deprecated": "This package is no longer supported.", + "node_modules/has-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-glob/-/has-glob-1.0.0.tgz", + "integrity": "sha512-D+8A457fBShSEI3tFCj65PAbT++5sKiFtdCdOam0gnfBgw9D277OERk+HM9qYJXmdVLZ/znez10SqHN0BBQ50g==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" + "is-glob": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "node_modules/has-glob/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.0" + }, "engines": { - "node": ">=6.9.0" + "node": ">=0.10.0" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" + "dunder-proto": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -14733,547 +15887,542 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", - "dev": true, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "license": "MIT", - "optional": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", "dev": true, "license": "MIT", - "engines": { - "node": ">=10" + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/get-tsconfig": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", - "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", + "node_modules/has-values/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "dev": true, "license": "MIT", "dependencies": { - "resolve-pkg-maps": "^1.0.0" + "kind-of": "^3.0.2" }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/github-slugger": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", - "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", - "license": "ISC" - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "license": "ISC", + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "dev": true, + "license": "MIT", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "is-buffer": "^1.1.5" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=0.10.0" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.3" + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" }, "engines": { - "node": ">=10.13.0" + "node": ">= 0.10" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" } }, - "node_modules/glob-promise": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/glob-promise/-/glob-promise-3.4.0.tgz", - "integrity": "sha512-q08RJ6O+eJn+dVanerAndJwIcumgbDdYiUT7zFQl3Wm1xD6fBKtah7H8ZJChj4wP+8C+QfeVy8xautR7rdmKEw==", - "dev": true, - "license": "ISC", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { - "@types/glob": "*" + "function-bind": "^1.1.2" }, "engines": { - "node": ">=4" - }, - "peerDependencies": { - "glob": "*" + "node": ">= 0.4" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "node_modules/hast-to-hyperscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz", + "integrity": "sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==", "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@types/unist": "^2.0.3", + "comma-separated-tokens": "^1.0.0", + "property-information": "^5.3.0", + "space-separated-tokens": "^1.0.0", + "style-to-object": "^0.3.0", + "unist-util-is": "^4.0.0", + "web-namespaces": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/hast-util-from-dom": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz", + "integrity": "sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==", "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "@types/hast": "^3.0.0", + "hastscript": "^9.0.0", + "web-namespaces": "^2.0.0" }, - "engines": { - "node": "*" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/global": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", - "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "node_modules/hast-util-from-dom/node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", "license": "MIT", "dependencies": { - "min-document": "^2.19.0", - "process": "^0.11.10" + "@types/unist": "*" } }, - "node_modules/globals": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz", - "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==", - "dev": true, + "node_modules/hast-util-from-dom/node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", "license": "MIT", - "engines": { - "node": ">=18" - }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, + "node_modules/hast-util-from-dom/node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", "license": "MIT", "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" + "@types/hast": "^3.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, + "node_modules/hast-util-from-dom/node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", "license": "MIT", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true, - "license": "MIT" - }, - "node_modules/goober": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz", - "integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==", + "node_modules/hast-util-from-dom/node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", "license": "MIT", - "peerDependencies": { - "csstype": "^3.0.10" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "node_modules/hast-util-from-dom/node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", "license": "MIT", - "engines": { - "node": ">= 0.4" - }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, - "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", - "dev": true, + "node_modules/hast-util-from-dom/node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", "license": "MIT", - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/handlebars/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", - "dev": true, + "node_modules/hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "node_modules/hast-util-from-html-isomorphic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz", + "integrity": "sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==", "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-dom": "^5.0.0", + "hast-util-from-html": "^2.0.0", + "unist-util-remove-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/has-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-glob/-/has-glob-1.0.0.tgz", - "integrity": "sha512-D+8A457fBShSEI3tFCj65PAbT++5sKiFtdCdOam0gnfBgw9D277OERk+HM9qYJXmdVLZ/znez10SqHN0BBQ50g==", - "dev": true, + "node_modules/hast-util-from-html-isomorphic/node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", "license": "MIT", "dependencies": { - "is-glob": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" + "@types/unist": "*" } }, - "node_modules/has-glob/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", - "dev": true, + "node_modules/hast-util-from-html-isomorphic/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/hast-util-from-html-isomorphic/node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", "license": "MIT", "dependencies": { - "is-extglob": "^2.1.0" + "@types/unist": "^3.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, + "node_modules/hast-util-from-html-isomorphic/node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0" + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", - "dev": true, + "node_modules/hast-util-from-html-isomorphic/node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", "license": "MIT", "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "node_modules/hast-util-from-html-isomorphic/node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "node_modules/hast-util-from-html/node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", "license": "MIT", "dependencies": { - "has-symbols": "^1.0.3" - }, + "@types/unist": "*" + } + }, + "node_modules/hast-util-from-html/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/hast-util-from-html/node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/hast-util-from-html/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", "engines": { - "node": ">= 0.4" + "node": ">=0.12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", - "dev": true, + "node_modules/hast-util-from-html/node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", "license": "MIT", "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", - "dev": true, + "node_modules/hast-util-from-html/node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", "license": "MIT", "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" + "@types/hast": "^3.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/has-values/node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true, - "license": "MIT" - }, - "node_modules/has-values/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "dev": true, + "node_modules/hast-util-from-html/node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", "license": "MIT", "dependencies": { - "kind-of": "^3.0.2" + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, + "node_modules/hast-util-from-html/node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", "license": "MIT", "dependencies": { - "is-buffer": "^1.1.5" + "entities": "^6.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", - "dev": true, + "node_modules/hast-util-from-html/node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/hash-base": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", - "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", - "dev": true, + "node_modules/hast-util-from-html/node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, + "node_modules/hast-util-from-html/node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/hast-util-from-html/node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", "license": "MIT", "dependencies": { - "function-bind": "^1.1.2" + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" }, - "engines": { - "node": ">= 0.4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/hast-to-hyperscript": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz", - "integrity": "sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==", - "dev": true, + "node_modules/hast-util-from-html/node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", "license": "MIT", "dependencies": { - "@types/unist": "^2.0.3", - "comma-separated-tokens": "^1.0.0", - "property-information": "^5.3.0", - "space-separated-tokens": "^1.0.0", - "style-to-object": "^0.3.0", - "unist-util-is": "^4.0.0", - "web-namespaces": "^1.0.0" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-from-html/node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/hast-util-from-parse5": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz", @@ -15317,19 +16466,27 @@ } }, "node_modules/hast-util-is-element": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.3.tgz", - "integrity": "sha512-O1bKah6mhgEq2WtVMk+Ta5K7pPMqsBBlmzysLdcwKVrqzZQ0CHqUPiIVspNhAG1rvxpvJjtGee17XfauZYKqVA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0", - "@types/unist": "^2.0.0" + "@types/hast": "^3.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-is-element/node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/hast-util-parse-selector": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", @@ -15700,6 +16857,19 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-to-html/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-to-html/node_modules/unist-util-visit": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", @@ -15824,6 +16994,37 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-to-text": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unist-util-find-after": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-text/node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/hast-util-to-text/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, "node_modules/hast-util-whitespace": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz", @@ -15918,382 +17119,689 @@ "integrity": "sha512-2HIpFMvvffsXHFUFjso0M9LqM+1Lm22BF+Df2ba+7QHJXjk63pWChEnI6YG27eaWqUdfnh5/Vy+OXrNTtepRsg==", "license": "MIT", "dependencies": { - "domhandler": "4.3.1", - "htmlparser2": "7.2.0" + "domhandler": "4.3.1", + "htmlparser2": "7.2.0" + } + }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.1", + "clean-css": "^4.2.3", + "commander": "^4.1.1", + "he": "^1.2.0", + "param-case": "^3.0.3", + "relateurl": "^0.2.7", + "terser": "^4.6.3" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/html-minifier-terser/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/html-minifier-terser/node_modules/terser": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz", + "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/html-minifier-terser/node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-react-parser": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/html-react-parser/-/html-react-parser-1.4.14.tgz", + "integrity": "sha512-pxhNWGie8Y+DGDpSh8cTa0k3g8PsDcwlfolA+XxYo1AGDeB6e2rdlyv4ptU9bOTiZ2i3fID+6kyqs86MN0FYZQ==", + "license": "MIT", + "dependencies": { + "domhandler": "4.3.1", + "html-dom-parser": "1.2.0", + "react-property": "2.0.0", + "style-to-js": "1.1.1" + }, + "peerDependencies": { + "react": "0.14 || 15 || 16 || 17 || 18" + } + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-to-react": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/html-to-react/-/html-to-react-1.7.0.tgz", + "integrity": "sha512-b5HTNaTGyOj5GGIMiWVr1k57egAZ/vGy0GGefnCQ1VW5hu9+eku8AXHtf2/DeD95cj/FKBKYa1J7SWBOX41yUQ==", + "license": "MIT", + "dependencies": { + "domhandler": "^5.0", + "htmlparser2": "^9.0", + "lodash.camelcase": "^4.3.0" + }, + "peerDependencies": { + "react": "^0.13.0 || ^0.14.0 || >=15" + } + }, + "node_modules/html-to-react/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/html-to-react/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/html-to-react/node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/html-to-react/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/html-to-react/node_modules/htmlparser2": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", + "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "entities": "^4.5.0" + } + }, + "node_modules/html-void-elements": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz", + "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/html-webpack-plugin": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.2.tgz", + "integrity": "sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/html-minifier-terser": "^5.0.0", + "@types/tapable": "^1.0.5", + "@types/webpack": "^4.41.8", + "html-minifier-terser": "^5.0.1", + "loader-utils": "^1.2.3", + "lodash": "^4.17.20", + "pretty-error": "^2.1.1", + "tapable": "^1.1.3", + "util.promisify": "1.0.0" + }, + "engines": { + "node": ">=6.9" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/html-webpack-plugin/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" } }, - "node_modules/html-entities": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", - "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "node_modules/html-webpack-plugin/node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/htmlparser2": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", + "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", { "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" + "url": "https://github.com/sponsors/fb55" } ], - "license": "MIT" + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.2", + "domutils": "^2.8.0", + "entities": "^3.0.1" + } }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" + "node_modules/htmlparser2/node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } }, - "node_modules/html-minifier-terser": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", - "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, "license": "MIT", "dependencies": { - "camel-case": "^4.1.1", - "clean-css": "^4.2.3", - "commander": "^4.1.1", - "he": "^1.2.0", - "param-case": "^3.0.3", - "relateurl": "^0.2.7", - "terser": "^4.6.3" - }, - "bin": { - "html-minifier-terser": "cli.js" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" }, "engines": { - "node": ">=6" + "node": ">= 0.8" } }, - "node_modules/html-minifier-terser/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">= 6" + "node": ">=10.17.0" } }, - "node_modules/html-minifier-terser/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/hyphenate-style-name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz", + "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==", + "license": "BSD-3-Clause" + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/html-minifier-terser/node_modules/terser": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz", - "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==", + "node_modules/icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", "dev": true, - "license": "BSD-2-Clause", + "license": "ISC", "dependencies": { - "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" - }, - "bin": { - "terser": "bin/terser" + "postcss": "^7.0.14" }, "engines": { - "node": ">=6.0.0" + "node": ">= 6" } }, - "node_modules/html-minifier-terser/node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==", "dev": true, "license": "MIT" }, - "node_modules/html-react-parser": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/html-react-parser/-/html-react-parser-1.4.14.tgz", - "integrity": "sha512-pxhNWGie8Y+DGDpSh8cTa0k3g8PsDcwlfolA+XxYo1AGDeB6e2rdlyv4ptU9bOTiZ2i3fID+6kyqs86MN0FYZQ==", + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, "license": "MIT", - "dependencies": { - "domhandler": "4.3.1", - "html-dom-parser": "1.2.0", - "react-property": "2.0.0", - "style-to-js": "1.1.1" - }, - "peerDependencies": { - "react": "0.14 || 15 || 16 || 17 || 18" + "engines": { + "node": ">= 4" } }, - "node_modules/html-tags": { + "node_modules/import-fresh": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", - "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", - "dev": true, + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, "engines": { - "node": ">=8" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/html-to-react": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/html-to-react/-/html-to-react-1.7.0.tgz", - "integrity": "sha512-b5HTNaTGyOj5GGIMiWVr1k57egAZ/vGy0GGefnCQ1VW5hu9+eku8AXHtf2/DeD95cj/FKBKYa1J7SWBOX41yUQ==", + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "license": "MIT", - "dependencies": { - "domhandler": "^5.0", - "htmlparser2": "^9.0", - "lodash.camelcase": "^4.3.0" - }, - "peerDependencies": { - "react": "^0.13.0 || ^0.14.0 || >=15" + "engines": { + "node": ">=4" } }, - "node_modules/html-to-react/node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/html-to-react/node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "license": "BSD-2-Clause", + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true, + "license": "ISC" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/html-to-react/node_modules/domutils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", - "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", - "license": "BSD-2-Clause", + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==", + "license": "MIT" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" + "engines": { + "node": ">= 0.4" } }, - "node_modules/html-to-react/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "license": "BSD-2-Clause", + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "node": ">=12" } }, - "node_modules/html-to-react/node_modules/htmlparser2": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", - "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], + "node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true, "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.1.0", - "entities": "^4.5.0" + "engines": { + "node": ">= 0.10" } }, - "node_modules/html-void-elements": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz", - "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==", + "node_modules/ip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "engines": { + "node": ">= 0.10" } }, - "node_modules/html-webpack-plugin": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.2.tgz", - "integrity": "sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A==", + "node_modules/is-accessor-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", + "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", "dev": true, "license": "MIT", "dependencies": { - "@types/html-minifier-terser": "^5.0.0", - "@types/tapable": "^1.0.5", - "@types/webpack": "^4.41.8", - "html-minifier-terser": "^5.0.1", - "loader-utils": "^1.2.3", - "lodash": "^4.17.20", - "pretty-error": "^2.1.1", - "tapable": "^1.1.3", - "util.promisify": "1.0.0" + "hasown": "^2.0.0" }, "engines": { - "node": ">=6.9" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "node": ">= 0.10" } }, - "node_modules/html-webpack-plugin/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, + "node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/html-webpack-plugin/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", - "dev": true, + "node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" }, - "engines": { - "node": ">=4.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/htmlparser2": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", - "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "dev": true, "license": "MIT", "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.2", - "domutils": "^2.8.0", - "entities": "^3.0.1" - } - }, - "node_modules/htmlparser2/node_modules/entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "license": "BSD-2-Clause", + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, "engines": { - "node": ">=0.12" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", - "dev": true, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "license": "MIT" }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, "engines": { - "node": ">=10.17.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hyphenate-style-name": { + "node_modules/is-bigint": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz", - "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==", - "license": "BSD-3-Clause" - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "has-bigints": "^1.0.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/icss-utils": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", - "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "postcss": "^7.0.14" + "binary-extensions": "^2.0.0" }, "engines": { - "node": ">= 6" + "node": ">=8" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", "funding": [ { "type": "github", @@ -16308,197 +17816,230 @@ "url": "https://feross.org/support" } ], - "license": "BSD-3-Clause" + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "node_modules/iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==", + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "node_modules/is-bun-module/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "license": "MIT", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "hasown": "^2.0.2" }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "node_modules/is-data-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "dev": true, "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, "engines": { - "node": ">=4" + "node": ">= 0.4" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, "engines": { - "node": ">=0.8.19" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/infer-owner": { + "node_modules/is-decimal": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true, - "license": "ISC" - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/inline-style-parser": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", - "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==", - "license": "MIT" - }, - "node_modules/internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { "node": ">= 0.4" } }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, "engines": { - "node": ">= 0.10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", - "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", + "node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, - "license": "MIT" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.10" + "node": ">=0.10.0" } }, - "node_modules/is-accessor-descriptor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", - "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "call-bound": "^1.0.3" }, "engines": { - "node": ">= 0.10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "node_modules/is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true, "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "license": "MIT", - "dependencies": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "engines": { + "node": ">=8" } }, - "node_modules/is-arguments": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", - "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "license": "MIT" + }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -16507,43 +18048,41 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" + "is-extglob": "^2.1.1" }, "engines": { - "node": ">= 0.4" - }, + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "license": "MIT", "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "node_modules/is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==", "license": "MIT" }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, "license": "MIT", - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, "engines": { "node": ">= 0.4" }, @@ -16551,14 +18090,25 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, "license": "MIT", "dependencies": { - "has-bigints": "^1.0.2" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -16567,28 +18117,44 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-binary-path": { + "node_modules/is-plain-obj": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "license": "MIT", "dependencies": { - "binary-extensions": "^2.0.0" + "isobject": "^3.0.1" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", - "dev": true, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -16597,58 +18163,58 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-bun-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", - "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, "license": "MIT", "dependencies": { - "semver": "^7.7.1" + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-bun-module/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, "engines": { "node": ">= 0.4" }, @@ -16656,13 +18222,15 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -16671,29 +18239,51 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-data-descriptor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", - "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" + "call-bound": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -16702,15 +18292,15 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -16719,1674 +18309,2052 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-decimal": { + "node_modules/is-whitespace-character": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", + "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==", + "dev": true, "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true, "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" } }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "node_modules/is-word-character": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", + "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==", "dev": true, "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, "license": "MIT", "dependencies": { - "is-plain-object": "^2.0.4" + "is-docker": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", - "dev": true, + "node_modules/isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", "license": "MIT", "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" } }, - "node_modules/is-finite": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", - "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "node_modules/isomorphic-unfetch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz", + "integrity": "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==", "dev": true, "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "node-fetch": "^2.6.1", + "unfetch": "^4.2.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "engines": { "node": ">=8" } }, - "node_modules/is-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", - "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", - "license": "MIT" + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } }, - "node_modules/is-generator-function": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", - "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "get-proto": "^1.0.0", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" + "semver": "^7.5.3" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/istanbul-lib-report/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, - "license": "MIT", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "is-extglob": "^2.1.1" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "node_modules/iterate-iterator": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.2.tgz", + "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==", + "dev": true, "license": "MIT", "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-in-browser": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", - "integrity": "sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==", - "license": "MIT" - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "node_modules/iterate-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", + "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "es-get-iterator": "^1.0.2", + "iterate-iterator": "^1.0.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", "dev": true, "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, "engines": { - "node": ">=0.12.0" + "node": ">= 0.4" } }, - "node_modules/is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "node_modules/jest-diff": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", + "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" + "chalk": "^2.0.1", + "diff-sequences": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 6" } }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "node_modules/jest-diff/node_modules/@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + }, "engines": { - "node": ">=8" + "node": ">= 6" } }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/jest-diff/node_modules/@types/istanbul-reports": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz", + "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", "dev": true, "license": "MIT", "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" } }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "license": "MIT" - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "node_modules/jest-diff/node_modules/@types/yargs": { + "version": "13.0.12", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.12.tgz", + "integrity": "sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ==", + "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@types/yargs-parser": "*" } }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "node_modules/jest-diff/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=6" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3" + "color-convert": "^1.9.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/jest-diff/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=4" } }, - "node_modules/is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "node_modules/jest-diff/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, + "color-name": "1.1.3" + } + }, + "node_modules/jest-diff/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-diff/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.8.0" } }, - "node_modules/is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "node_modules/jest-diff/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4" } }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", "dev": true, "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.16" + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 6" } }, - "node_modules/is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "node_modules/jest-diff/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "node_modules/jest-diff/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "has-flag": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=4" } }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "node_modules/jest-get-type": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 6" } }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 10.13.0" } }, - "node_modules/is-whitespace-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", - "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==", - "dev": true, + "node_modules/jquery": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } + "peer": true }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "license": "MIT" + }, + "node_modules/js-string-escape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", + "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/is-word-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", - "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==", + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0" + "bin": { + "jsesc": "bin/jsesc" }, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, "license": "MIT" }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/isomorphic-fetch": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", - "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, "license": "MIT", "dependencies": { - "node-fetch": "^2.6.1", - "whatwg-fetch": "^3.4.1" + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/isomorphic-unfetch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz", - "integrity": "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==", - "dev": true, + "node_modules/jss": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.10.0.tgz", + "integrity": "sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==", "license": "MIT", "dependencies": { - "node-fetch": "^2.6.1", - "unfetch": "^4.2.0" - } - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/jss" } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/jss-plugin-camel-case": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz", + "integrity": "sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==", + "license": "MIT", "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.10.0" } }, - "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, + "node_modules/jss-plugin-default-unit": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz", + "integrity": "sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==", "license": "MIT", "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" } }, - "node_modules/istanbul-lib-report/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "node_modules/jss-plugin-global": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz", + "integrity": "sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" } }, - "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/jss-plugin-nested": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz", + "integrity": "sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==", + "license": "MIT", "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" } }, - "node_modules/iterate-iterator": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.2.tgz", - "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==", - "dev": true, + "node_modules/jss-plugin-props-sort": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz", + "integrity": "sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==", "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" } }, - "node_modules/iterate-value": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", - "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", - "dev": true, + "node_modules/jss-plugin-rule-value-function": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz", + "integrity": "sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==", "license": "MIT", "dependencies": { - "es-get-iterator": "^1.0.2", - "iterate-iterator": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" } }, - "node_modules/iterator.prototype": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", - "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", - "dev": true, + "node_modules/jss-plugin-vendor-prefixer": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz", + "integrity": "sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==", "license": "MIT", "dependencies": { - "define-data-property": "^1.1.4", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "get-proto": "^1.0.0", - "has-symbols": "^1.1.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.10.0" } }, - "node_modules/jest-diff": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", - "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^2.0.1", - "diff-sequences": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" }, "engines": { - "node": ">= 6" + "node": ">=4.0" } }, - "node_modules/jest-diff/node_modules/@jest/types": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", - "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "node_modules/junk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz", + "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==", "dev": true, "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^13.0.0" - }, "engines": { - "node": ">= 6" + "node": ">=8" } }, - "node_modules/jest-diff/node_modules/@types/istanbul-reports": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz", - "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", - "dev": true, + "node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==", + "license": "MIT" + }, + "node_modules/katex": { + "version": "0.16.22", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.22.tgz", + "integrity": "sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "*", - "@types/istanbul-lib-report": "*" + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" } }, - "node_modules/jest-diff/node_modules/@types/yargs": { - "version": "13.0.12", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.12.tgz", - "integrity": "sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ==", + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", "dependencies": { - "@types/yargs-parser": "*" + "json-buffer": "3.0.1" } }, - "node_modules/jest-diff/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true, "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, "engines": { - "node": ">=4" + "node": ">=6" } }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, "engines": { - "node": ">=4" + "node": ">= 8" } }, - "node_modules/jest-diff/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/lazy-universal-dotenv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz", + "integrity": "sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "color-name": "1.1.3" + "@babel/runtime": "^7.5.0", + "app-root-dir": "^1.0.2", + "core-js": "^3.0.4", + "dotenv": "^8.0.0", + "dotenv-expand": "^5.1.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=6.0.0", + "yarn": ">=1.0.0" } }, - "node_modules/jest-diff/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/jest-diff/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "node_modules/lazy-universal-dotenv/node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "engines": { - "node": ">=0.8.0" + "node": ">=10" } }, - "node_modules/jest-diff/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, "engines": { - "node": ">=4" + "node": ">= 0.8.0" } }, - "node_modules/jest-diff/node_modules/pretty-format": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", - "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" }, "engines": { - "node": ">= 6" + "node": ">=0.10.0" } }, - "node_modules/jest-diff/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/jest-diff/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/load-json-file/node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "has-flag": "^3.0.0" + "error-ex": "^1.2.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "node_modules/load-json-file/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, "license": "MIT", + "optional": true, "engines": { - "node": ">= 6" + "node": ">=0.10.0" } }, - "node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "node_modules/load-json-file/node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" + "is-utf8": "^0.2.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">=0.10.0" } }, - "node_modules/jquery": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", - "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", - "license": "MIT", - "peer": true - }, - "node_modules/js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", - "license": "MIT" - }, - "node_modules/js-string-escape": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", - "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", + "node_modules/loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=4.3.0 <5.0.0 || >=5.10" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=8.9.0" } }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" + "dependencies": { + "p-locate": "^5.0.0" }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", "license": "MIT" }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, "license": "MIT" }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, "license": "MIT" }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", "dev": true, "license": "MIT" }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", "license": "MIT", - "bin": { - "json5": "lib/cli.js" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" }, - "engines": { - "node": ">=6" + "bin": { + "loose-envify": "cli.js" } }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "node_modules/loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha512-RPNliZOFkqFumDhvYqOaNY4Uz9oJM2K9tC6JWsJJsNdhuONW4LQHRBpb0qf4pJApVffI5N39SwzWZJuEhfd7eQ==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "universalify": "^2.0.0" + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/jss": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss/-/jss-10.10.0.tgz", - "integrity": "sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==", + "node_modules/lowdb": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowdb/-/lowdb-1.0.0.tgz", + "integrity": "sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.3.1", - "csstype": "^3.0.2", - "is-in-browser": "^1.1.3", - "tiny-warning": "^1.0.2" + "graceful-fs": "^4.1.3", + "is-promise": "^2.1.0", + "lodash": "4", + "pify": "^3.0.0", + "steno": "^0.4.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/jss" + "engines": { + "node": ">=4" } }, - "node_modules/jss-plugin-camel-case": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz", - "integrity": "sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==", + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.3.1", - "hyphenate-style-name": "^1.0.3", - "jss": "10.10.0" + "tslib": "^2.0.3" + } + }, + "node_modules/lowlight": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "license": "MIT", + "dependencies": { + "fault": "^1.0.0", + "highlight.js": "~10.7.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lowlight/node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" } }, - "node_modules/jss-plugin-default-unit": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz", - "integrity": "sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==", - "license": "MIT", + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", "dependencies": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0" + "yallist": "^3.0.2" } }, - "node_modules/jss-plugin-global": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz", - "integrity": "sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==", + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0" + "bin": { + "lz-string": "bin/bin.js" } }, - "node_modules/jss-plugin-nested": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz", - "integrity": "sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==", + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0", - "tiny-warning": "^1.0.2" + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" } }, - "node_modules/jss-plugin-props-sort": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz", - "integrity": "sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==", + "node_modules/make-dir/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0" + "engines": { + "node": ">=6" } }, - "node_modules/jss-plugin-rule-value-function": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz", - "integrity": "sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==", + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true, "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.3.1", - "jss": "10.10.0", - "tiny-warning": "^1.0.2" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/jss-plugin-vendor-prefixer": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz", - "integrity": "sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==", + "node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.3.1", - "css-vendor": "^2.0.8", - "jss": "10.10.0" + "optional": true, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "node_modules/map-or-similar": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", + "integrity": "sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==", + "license": "MIT" + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", "dev": true, "license": "MIT", "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" + "object-visit": "^1.0.0" }, "engines": { - "node": ">=4.0" + "node": ">=0.10.0" } }, - "node_modules/junk": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz", - "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==", + "node_modules/markdown-escapes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", + "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/jwt-decode": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", - "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==", - "license": "MIT" + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, + "node_modules/match-sorter": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.4.tgz", + "integrity": "sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg==", "license": "MIT", "dependencies": { - "json-buffer": "3.0.1" + "@babel/runtime": "^7.23.8", + "remove-accents": "0.5.0" } }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", - "dev": true, + "node_modules/mdast-add-list-metadata": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdast-add-list-metadata/-/mdast-add-list-metadata-1.0.1.tgz", + "integrity": "sha512-fB/VP4MJ0LaRsog7hGPxgOrSL3gE/2uEdZyDuSEnKCv/8IkYHiDkIQSbChiJoHyxZZXZ9bzckyRk+vNxFzh8rA==", "license": "MIT", - "engines": { - "node": ">= 8" + "dependencies": { + "unist-util-visit-parents": "1.1.2" } }, - "node_modules/lazy-universal-dotenv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz", - "integrity": "sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ==", + "node_modules/mdast-squeeze-paragraphs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz", + "integrity": "sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.5.0", - "app-root-dir": "^1.0.2", - "core-js": "^3.0.4", - "dotenv": "^8.0.0", - "dotenv-expand": "^5.1.0" + "unist-util-remove": "^2.0.0" }, - "engines": { - "node": ">=6.0.0", - "npm": ">=6.0.0", - "yarn": ">=1.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/lazy-universal-dotenv/node_modules/dotenv": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", - "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "node_modules/mdast-util-definitions": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz", + "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", + "dependencies": { + "unist-util-visit": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.2.tgz", + "integrity": "sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, + "node_modules/mdast-util-find-and-replace/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "@types/unist": "^2.0.0" }, - "engines": { - "node": ">= 0.8.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "license": "MIT" - }, - "node_modules/load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", - "dev": true, + "node_modules/mdast-util-find-and-replace/node_modules/unist-util-visit-parents": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", "license": "MIT", - "optional": true, "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/load-json-file/node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", - "dev": true, + "node_modules/mdast-util-gfm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.2.tgz", + "integrity": "sha512-qvZ608nBppZ4icQlhQQIAdc6S3Ffj9RGmzwUKUWuEICFnd1LVkN3EktF7ZHAgfcEdvZB5owU9tQgt99e2TlLjg==", "license": "MIT", - "optional": true, "dependencies": { - "error-ex": "^1.2.0" + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-gfm-autolink-literal": "^1.0.0", + "mdast-util-gfm-footnote": "^1.0.0", + "mdast-util-gfm-strikethrough": "^1.0.0", + "mdast-util-gfm-table": "^1.0.0", + "mdast-util-gfm-task-list-item": "^1.0.0", + "mdast-util-to-markdown": "^1.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/load-json-file/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.3.tgz", + "integrity": "sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA==", "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" + "dependencies": { + "@types/mdast": "^3.0.0", + "ccount": "^2.0.0", + "mdast-util-find-and-replace": "^2.0.0", + "micromark-util-character": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/load-json-file/node_modules/strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", - "dev": true, + "node_modules/mdast-util-gfm-footnote": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.2.tgz", + "integrity": "sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ==", "license": "MIT", - "optional": true, "dependencies": { - "is-utf8": "^0.2.0" + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0", + "micromark-util-normalize-identifier": "^1.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/loader-runner": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", - "dev": true, + "node_modules/mdast-util-gfm-footnote/node_modules/micromark-util-normalize-identifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz", + "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=4.3.0 <5.0.0 || >=5.10" + "dependencies": { + "micromark-util-symbol": "^1.0.0" } }, - "node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.3.tgz", + "integrity": "sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ==", "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0" }, - "engines": { - "node": ">=8.9.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, + "node_modules/mdast-util-gfm-table": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.7.tgz", + "integrity": "sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg==", "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" + "@types/mdast": "^3.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-to-markdown": "^1.3.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "license": "MIT" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/longest-streak": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "node_modules/mdast-util-gfm-table/node_modules/mdast-util-from-markdown": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz", + "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==", "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table/node_modules/micromark": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz", + "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" } }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "node_modules/mdast-util-gfm-table/node_modules/micromark-core-commonmark": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz", + "integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" } }, - "node_modules/loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha512-RPNliZOFkqFumDhvYqOaNY4Uz9oJM2K9tC6JWsJJsNdhuONW4LQHRBpb0qf4pJApVffI5N39SwzWZJuEhfd7eQ==", - "dev": true, + "node_modules/mdast-util-gfm-table/node_modules/micromark-factory-destination": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz", + "integrity": "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "optional": true, "dependencies": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/lowdb": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lowdb/-/lowdb-1.0.0.tgz", - "integrity": "sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ==", + "node_modules/mdast-util-gfm-table/node_modules/micromark-factory-label": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz", + "integrity": "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "graceful-fs": "^4.1.3", - "is-promise": "^2.1.0", - "lodash": "4", - "pify": "^3.0.0", - "steno": "^0.4.1" - }, - "engines": { - "node": ">=4" + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" } }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, + "node_modules/mdast-util-gfm-table/node_modules/micromark-factory-title": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz", + "integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "tslib": "^2.0.3" + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/lowlight": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", - "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "node_modules/mdast-util-gfm-table/node_modules/micromark-factory-whitespace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz", + "integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "fault": "^1.0.0", - "highlight.js": "~10.7.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/lowlight/node_modules/highlight.js": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", - "license": "BSD-3-Clause", - "engines": { - "node": "*" + "node_modules/mdast-util-gfm-table/node_modules/micromark-util-chunked": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz", + "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0" } }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", + "node_modules/mdast-util-gfm-table/node_modules/micromark-util-classify-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz", + "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "yallist": "^3.0.2" + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "dev": true, + "node_modules/mdast-util-gfm-table/node_modules/micromark-util-combine-extensions": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz", + "integrity": "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "bin": { - "lz-string": "bin/bin.js" + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, + "node_modules/mdast-util-gfm-table/node_modules/micromark-util-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", + "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mdast-util-gfm-table/node_modules/micromark-util-html-tag-name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz", + "integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mdast-util-gfm-table/node_modules/micromark-util-normalize-identifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz", + "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" + "micromark-util-symbol": "^1.0.0" } }, - "node_modules/make-dir/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, + "node_modules/mdast-util-gfm-table/node_modules/micromark-util-resolve-all": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz", + "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" + "dependencies": { + "micromark-util-types": "^1.0.0" } }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", - "dev": true, + "node_modules/mdast-util-gfm-table/node_modules/micromark-util-sanitize-uri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", + "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" } }, - "node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true, + "node_modules/mdast-util-gfm-table/node_modules/micromark-util-subtokenize": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz", + "integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" } }, - "node_modules/map-or-similar": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", - "integrity": "sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==", - "license": "MIT" - }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", - "dev": true, + "node_modules/mdast-util-gfm-table/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", "license": "MIT", "dependencies": { - "object-visit": "^1.0.0" + "@types/unist": "^2.0.0" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/markdown-escapes": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", - "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==", - "dev": true, - "license": "MIT", "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/markdown-table": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", - "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "node_modules/mdast-util-gfm-task-list-item": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.2.tgz", + "integrity": "sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ==", "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/match-sorter": { - "version": "6.3.4", - "resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.4.tgz", - "integrity": "sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg==", + "node_modules/mdast-util-gfm/node_modules/mdast-util-from-markdown": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz", + "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.8", - "remove-accents": "0.5.0" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, + "node_modules/mdast-util-gfm/node_modules/micromark": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz", + "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" } }, - "node_modules/mdast-add-list-metadata": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdast-add-list-metadata/-/mdast-add-list-metadata-1.0.1.tgz", - "integrity": "sha512-fB/VP4MJ0LaRsog7hGPxgOrSL3gE/2uEdZyDuSEnKCv/8IkYHiDkIQSbChiJoHyxZZXZ9bzckyRk+vNxFzh8rA==", + "node_modules/mdast-util-gfm/node_modules/micromark-core-commonmark": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz", + "integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "unist-util-visit-parents": "1.1.2" + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" } }, - "node_modules/mdast-squeeze-paragraphs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz", - "integrity": "sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==", - "dev": true, + "node_modules/mdast-util-gfm/node_modules/micromark-factory-destination": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz", + "integrity": "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "unist-util-remove": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/mdast-util-definitions": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz", - "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==", - "dev": true, + "node_modules/mdast-util-gfm/node_modules/micromark-factory-label": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz", + "integrity": "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "unist-util-visit": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" } }, - "node_modules/mdast-util-find-and-replace": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.2.tgz", - "integrity": "sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw==", + "node_modules/mdast-util-gfm/node_modules/micromark-factory-title": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz", + "integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@types/mdast": "^3.0.0", - "escape-string-regexp": "^5.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/mdast-util-find-and-replace/node_modules/unist-util-is": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", - "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "node_modules/mdast-util-gfm/node_modules/micromark-factory-whitespace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz", + "integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" } }, - "node_modules/mdast-util-find-and-replace/node_modules/unist-util-visit-parents": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", - "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", + "node_modules/mdast-util-gfm/node_modules/micromark-util-chunked": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz", + "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-util-symbol": "^1.0.0" } }, - "node_modules/mdast-util-from-markdown": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz", - "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==", + "node_modules/mdast-util-gfm/node_modules/micromark-util-classify-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz", + "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "mdast-util-to-string": "^3.1.0", - "micromark": "^3.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-decode-string": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "unist-util-stringify-position": "^3.0.0", - "uvu": "^0.5.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-util-types": "^1.0.0" } }, - "node_modules/mdast-util-gfm": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.2.tgz", - "integrity": "sha512-qvZ608nBppZ4icQlhQQIAdc6S3Ffj9RGmzwUKUWuEICFnd1LVkN3EktF7ZHAgfcEdvZB5owU9tQgt99e2TlLjg==", + "node_modules/mdast-util-gfm/node_modules/micromark-util-combine-extensions": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz", + "integrity": "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "mdast-util-from-markdown": "^1.0.0", - "mdast-util-gfm-autolink-literal": "^1.0.0", - "mdast-util-gfm-footnote": "^1.0.0", - "mdast-util-gfm-strikethrough": "^1.0.0", - "mdast-util-gfm-table": "^1.0.0", - "mdast-util-gfm-task-list-item": "^1.0.0", - "mdast-util-to-markdown": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/mdast-util-gfm/node_modules/micromark-util-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", + "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mdast-util-gfm/node_modules/micromark-util-html-tag-name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz", + "integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mdast-util-gfm/node_modules/micromark-util-normalize-identifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz", + "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0" } }, - "node_modules/mdast-util-gfm-autolink-literal": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.3.tgz", - "integrity": "sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA==", + "node_modules/mdast-util-gfm/node_modules/micromark-util-resolve-all": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz", + "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@types/mdast": "^3.0.0", - "ccount": "^2.0.0", - "mdast-util-find-and-replace": "^2.0.0", - "micromark-util-character": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-util-types": "^1.0.0" } }, - "node_modules/mdast-util-gfm-footnote": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.2.tgz", - "integrity": "sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ==", + "node_modules/mdast-util-gfm/node_modules/micromark-util-sanitize-uri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", + "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@types/mdast": "^3.0.0", - "mdast-util-to-markdown": "^1.3.0", - "micromark-util-normalize-identifier": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" } }, - "node_modules/mdast-util-gfm-strikethrough": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.3.tgz", - "integrity": "sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ==", + "node_modules/mdast-util-gfm/node_modules/micromark-util-subtokenize": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz", + "integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@types/mdast": "^3.0.0", - "mdast-util-to-markdown": "^1.3.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" } }, - "node_modules/mdast-util-gfm-table": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.7.tgz", - "integrity": "sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg==", + "node_modules/mdast-util-gfm/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", "license": "MIT", "dependencies": { - "@types/mdast": "^3.0.0", - "markdown-table": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "mdast-util-to-markdown": "^1.3.0" + "@types/unist": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-gfm-task-list-item": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.2.tgz", - "integrity": "sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ==", + "node_modules/mdast-util-math": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-2.0.2.tgz", + "integrity": "sha512-8gmkKVp9v6+Tgjtq6SYx9kGPpTf6FVYRa53/DLh479aldR9AyP48qeVOgNZ5X7QUK7nOy4yw7vg6mbiGcs9jWQ==", "license": "MIT", "dependencies": { "@types/mdast": "^3.0.0", + "longest-streak": "^3.0.0", "mdast-util-to-markdown": "^1.3.0" }, "funding": { @@ -18682,75 +20650,6 @@ "dev": true, "license": "MIT" }, - "node_modules/micromark": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz", - "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "micromark-core-commonmark": "^1.0.1", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-encode": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", - "micromark-util-subtokenize": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.1", - "uvu": "^0.5.0" - } - }, - "node_modules/micromark-core-commonmark": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz", - "integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-factory-destination": "^1.0.0", - "micromark-factory-label": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-factory-title": "^1.0.0", - "micromark-factory-whitespace": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-classify-character": "^1.0.0", - "micromark-util-html-tag-name": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-subtokenize": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.1", - "uvu": "^0.5.0" - } - }, "node_modules/micromark-extension-gfm": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-2.0.3.tgz", @@ -18787,6 +20686,43 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", + "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-sanitize-uri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", + "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, "node_modules/micromark-extension-gfm-footnote": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.1.2.tgz", @@ -18807,72 +20743,41 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-extension-gfm-strikethrough": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.7.tgz", - "integrity": "sha512-sX0FawVE1o3abGk3vRjOH50L5TTLr3b5XMqnP9YDRb34M0v5OoZhG+OHFz1OffZ9dlwgpTBKaT4XW/AsUVnSDw==", - "license": "MIT", - "dependencies": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-classify-character": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-table": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.7.tgz", - "integrity": "sha512-3ZORTHtcSnMQEKtAOsBQ9/oHp9096pI/UvdPtN7ehKvrmZZ2+bbWhi0ln+I9drmwXMt5boocn6OlwQzNXeVeqw==", - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-tagfilter": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.2.tgz", - "integrity": "sha512-5XWB9GbAUSHTn8VPU8/1DBXMuKYT5uOgEjJb8gN3mW0PNW5OPHpSdojoqf+iq1xo7vWzw/P8bAHY0n6ijpXF7g==", - "license": "MIT", - "dependencies": { - "micromark-util-types": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-task-list-item": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.5.tgz", - "integrity": "sha512-RMFXl2uQ0pNQy6Lun2YBYT9g9INXtWJULgbt01D/x8/6yJ2qpKyzdZD3pi6UIkzF++Da49xAelVKUeUMqd5eIQ==", + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-core-commonmark": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz", + "integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", + "micromark-util-types": "^1.0.1", "uvu": "^0.5.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-factory-destination": { + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-destination": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz", "integrity": "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==", @@ -18893,7 +20798,7 @@ "micromark-util-types": "^1.0.0" } }, - "node_modules/micromark-factory-label": { + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-label": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz", "integrity": "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==", @@ -18915,10 +20820,10 @@ "uvu": "^0.5.0" } }, - "node_modules/micromark-factory-space": { + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-title": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", - "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz", + "integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==", "funding": [ { "type": "GitHub Sponsors", @@ -18931,14 +20836,16 @@ ], "license": "MIT", "dependencies": { + "micromark-factory-space": "^1.0.0", "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" } }, - "node_modules/micromark-factory-title": { + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-whitespace": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz", - "integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz", + "integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==", "funding": [ { "type": "GitHub Sponsors", @@ -18957,10 +20864,29 @@ "micromark-util-types": "^1.0.0" } }, - "node_modules/micromark-factory-whitespace": { + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-chunked": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz", - "integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz", + "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-classify-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz", + "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==", "funding": [ { "type": "GitHub Sponsors", @@ -18973,16 +20899,66 @@ ], "license": "MIT", "dependencies": { - "micromark-factory-space": "^1.0.0", "micromark-util-character": "^1.0.0", "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" } }, - "node_modules/micromark-util-character": { + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", + "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-html-tag-name": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", - "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz", + "integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-normalize-identifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz", + "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-resolve-all": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz", + "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==", "funding": [ { "type": "GitHub Sponsors", @@ -18995,11 +20971,71 @@ ], "license": "MIT", "dependencies": { - "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" } }, - "node_modules/micromark-util-chunked": { + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-sanitize-uri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", + "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-subtokenize": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz", + "integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.7.tgz", + "integrity": "sha512-sX0FawVE1o3abGk3vRjOH50L5TTLr3b5XMqnP9YDRb34M0v5OoZhG+OHFz1OffZ9dlwgpTBKaT4XW/AsUVnSDw==", + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-chunked": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz", "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==", @@ -19018,10 +21054,97 @@ "micromark-util-symbol": "^1.0.0" } }, - "node_modules/micromark-util-classify-character": { + "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-classify-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz", + "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-resolve-all": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz", + "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.7.tgz", + "integrity": "sha512-3ZORTHtcSnMQEKtAOsBQ9/oHp9096pI/UvdPtN7ehKvrmZZ2+bbWhi0ln+I9drmwXMt5boocn6OlwQzNXeVeqw==", + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.2.tgz", + "integrity": "sha512-5XWB9GbAUSHTn8VPU8/1DBXMuKYT5uOgEjJb8gN3mW0PNW5OPHpSdojoqf+iq1xo7vWzw/P8bAHY0n6ijpXF7g==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.5.tgz", + "integrity": "sha512-RMFXl2uQ0pNQy6Lun2YBYT9g9INXtWJULgbt01D/x8/6yJ2qpKyzdZD3pi6UIkzF++Da49xAelVKUeUMqd5eIQ==", + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm/node_modules/micromark-util-chunked": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz", - "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz", + "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==", "funding": [ { "type": "GitHub Sponsors", @@ -19034,12 +21157,10 @@ ], "license": "MIT", "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" + "micromark-util-symbol": "^1.0.0" } }, - "node_modules/micromark-util-combine-extensions": { + "node_modules/micromark-extension-gfm/node_modules/micromark-util-combine-extensions": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz", "integrity": "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==", @@ -19059,29 +21180,29 @@ "micromark-util-types": "^1.0.0" } }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz", - "integrity": "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/micromark-extension-math": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-2.1.2.tgz", + "integrity": "sha512-es0CcOV89VNS9wFmyn+wyFTKweXGW4CEvdaAca6SWRWPyYCbBisnjaHLjWO4Nszuiud84jCpkHsqAJoa768Pvg==", "license": "MIT", "dependencies": { - "micromark-util-symbol": "^1.0.0" + "@types/katex": "^0.16.0", + "katex": "^0.16.0", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-util-decode-string": { + "node_modules/micromark-factory-space": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz", - "integrity": "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", "funding": [ { "type": "GitHub Sponsors", @@ -19094,67 +21215,14 @@ ], "license": "MIT", "dependencies": { - "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-symbol": "^1.0.0" + "micromark-util-types": "^1.0.0" } }, - "node_modules/micromark-util-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", - "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-html-tag-name": { + "node_modules/micromark-util-character": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz", - "integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz", - "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^1.0.0" - } - }, - "node_modules/micromark-util-resolve-all": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz", - "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", "funding": [ { "type": "GitHub Sponsors", @@ -19167,13 +21235,14 @@ ], "license": "MIT", "dependencies": { + "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" } }, - "node_modules/micromark-util-sanitize-uri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", - "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz", + "integrity": "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==", "funding": [ { "type": "GitHub Sponsors", @@ -19186,15 +21255,13 @@ ], "license": "MIT", "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-encode": "^1.0.0", "micromark-util-symbol": "^1.0.0" } }, - "node_modules/micromark-util-subtokenize": { + "node_modules/micromark-util-decode-string": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz", - "integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz", + "integrity": "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==", "funding": [ { "type": "GitHub Sponsors", @@ -19207,10 +21274,10 @@ ], "license": "MIT", "dependencies": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" } }, "node_modules/micromark-util-symbol": { @@ -19613,7 +21680,6 @@ "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, "funding": [ { "type": "github", @@ -21022,7 +23088,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, "license": "MIT" }, "node_modules/postcss/node_modules/picocolors": { @@ -21465,13 +23530,12 @@ } }, "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" }, "engines": { "node": ">=0.10.0" @@ -21530,55 +23594,30 @@ "license": "MIT" }, "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - }, - "peerDependencies": { - "react": "17.0.2" - } - }, - "node_modules/react-element-to-jsx-string": { - "version": "14.3.4", - "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-14.3.4.tgz", - "integrity": "sha512-t4ZwvV6vwNxzujDQ+37bspnLwA4JlgUPWhLjBJWsNIDceAf6ZKUTCjdm08cN6WeZ5pTMKiCJkmAYnpmR4Bm+dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@base2/pretty-print-object": "1.0.1", - "is-plain-object": "5.0.0", - "react-is": "17.0.2" + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1", - "react-dom": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1" - } - }, - "node_modules/react-element-to-jsx-string/node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "react": "^18.3.1" } }, - "node_modules/react-input-autosize": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz", - "integrity": "sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==", + "node_modules/react-drag-drop-files": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/react-drag-drop-files/-/react-drag-drop-files-3.1.0.tgz", + "integrity": "sha512-b2T4NyJP4MLHw/OYd7fuoMLz5NqO5BgqJRIx+rYGY/aihxTF6d4E/9uYezmYdd7KaC6KvnlA0UW2h+jlFQyeWA==", "license": "MIT", "dependencies": { - "prop-types": "^15.5.8" + "prop-types": "^15.7.2", + "styled-components": "^6.1.11" }, "peerDependencies": { - "react": "^16.3.0 || ^17.0.0" + "react": ">=18.0.0", + "react-dom": ">=18.0.0" } }, "node_modules/react-is": { @@ -21772,56 +23811,6 @@ "react-dom": ">=16.8" } }, - "node_modules/react-select": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/react-select/-/react-select-3.2.0.tgz", - "integrity": "sha512-B/q3TnCZXEKItO0fFN/I0tWOX3WJvi/X2wtdffmwSQVRwg5BpValScTO1vdic9AxlUgmeSzib2hAZAwIUQUZGQ==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.4.4", - "@emotion/cache": "^10.0.9", - "@emotion/core": "^10.0.9", - "@emotion/css": "^10.0.9", - "memoize-one": "^5.0.0", - "prop-types": "^15.6.0", - "react-input-autosize": "^3.0.0", - "react-transition-group": "^4.3.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" - } - }, - "node_modules/react-select/node_modules/@emotion/cache": { - "version": "10.0.29", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", - "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", - "license": "MIT", - "dependencies": { - "@emotion/sheet": "0.9.4", - "@emotion/stylis": "0.8.5", - "@emotion/utils": "0.11.3", - "@emotion/weak-memoize": "0.2.5" - } - }, - "node_modules/react-select/node_modules/@emotion/sheet": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz", - "integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==", - "license": "MIT" - }, - "node_modules/react-select/node_modules/@emotion/utils": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", - "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==", - "license": "MIT" - }, - "node_modules/react-select/node_modules/@emotion/weak-memoize": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", - "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==", - "license": "MIT" - }, "node_modules/react-smooth": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", @@ -22349,6 +24338,19 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/rehype-attr/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/rehype-attr/node_modules/unist-util-visit": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", @@ -22437,6 +24439,20 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/rehype-autolink-headings/node_modules/hast-util-is-element": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.3.tgz", + "integrity": "sha512-O1bKah6mhgEq2WtVMk+Ta5K7pPMqsBBlmzysLdcwKVrqzZQ0CHqUPiIVspNhAG1rvxpvJjtGee17XfauZYKqVA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/rehype-autolink-headings/node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -22491,6 +24507,19 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/rehype-autolink-headings/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/rehype-autolink-headings/node_modules/unist-util-visit": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", @@ -22615,10 +24644,23 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-ignore/node_modules/unist-util-is": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", - "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "node_modules/rehype-ignore/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-ignore/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", "license": "MIT", "dependencies": { "@types/unist": "^2.0.0" @@ -22687,6 +24729,95 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/rehype-katex": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.1.tgz", + "integrity": "sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/katex": "^0.16.0", + "hast-util-from-html-isomorphic": "^2.0.0", + "hast-util-to-text": "^4.0.0", + "katex": "^0.16.0", + "unist-util-visit-parents": "^6.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-katex/node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/rehype-katex/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/rehype-katex/node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-katex/node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-katex/node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-katex/node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/rehype-parse": { "version": "8.0.5", "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-8.0.5.tgz", @@ -22833,6 +24964,19 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/rehype-parse/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/rehype-parse/node_modules/vfile": { "version": "5.3.7", "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", @@ -23330,6 +25474,19 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/rehype-raw/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/rehype-raw/node_modules/unist-util-visit": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", @@ -23501,6 +25658,19 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/rehype-rewrite/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/rehype-rewrite/node_modules/unist-util-visit": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", @@ -23666,6 +25836,19 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/rehype-slug/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/rehype-slug/node_modules/unist-util-visit": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", @@ -23791,37 +25974,181 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-stringify/node_modules/vfile": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", - "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "node_modules/rehype-stringify/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-stringify/node_modules/vfile": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-stringify/node_modules/vfile-message": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", + "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/rehype/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rehype/node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/rehype/node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype/node_modules/vfile": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype/node_modules/vfile-message": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", + "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remark-footnotes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-2.0.0.tgz", + "integrity": "sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==", + "dev": true, "license": "MIT", - "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" - }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-stringify/node_modules/vfile-message": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", - "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "node_modules/remark-gfm": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz", + "integrity": "sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==", "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^3.0.0" + "@types/mdast": "^3.0.0", + "mdast-util-gfm": "^2.0.0", + "micromark-extension-gfm": "^2.0.0", + "unified": "^10.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/rehype/node_modules/bail": { + "node_modules/remark-gfm/node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", @@ -23831,7 +26158,7 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/rehype/node_modules/is-plain-obj": { + "node_modules/remark-gfm/node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", @@ -23843,7 +26170,7 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rehype/node_modules/trough": { + "node_modules/remark-gfm/node_modules/trough": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", @@ -23853,7 +26180,7 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/rehype/node_modules/unified": { + "node_modules/remark-gfm/node_modules/unified": { "version": "10.1.2", "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", @@ -23872,7 +26199,20 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/rehype/node_modules/vfile": { + "node_modules/remark-gfm/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm/node_modules/vfile": { "version": "5.3.7", "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", @@ -23888,7 +26228,7 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/rehype/node_modules/vfile-message": { + "node_modules/remark-gfm/node_modules/vfile-message": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", @@ -23902,36 +26242,15 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/remark-footnotes": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-2.0.0.tgz", - "integrity": "sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==", - "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-gfm": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz", - "integrity": "sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==", + "node_modules/remark-math": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/remark-math/-/remark-math-5.1.1.tgz", + "integrity": "sha512-cE5T2R/xLVtfFI4cCePtiRn+e6jKMtFDR3P8V3qpv8wpKjwvHoBA4eJzvX+nVrnlNy0911bdGmuspCSwetfYHw==", "license": "MIT", "dependencies": { "@types/mdast": "^3.0.0", - "mdast-util-gfm": "^2.0.0", - "micromark-extension-gfm": "^2.0.0", + "mdast-util-math": "^2.0.0", + "micromark-extension-math": "^2.0.0", "unified": "^10.0.0" }, "funding": { @@ -23939,7 +26258,7 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-gfm/node_modules/bail": { + "node_modules/remark-math/node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", @@ -23949,7 +26268,7 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/remark-gfm/node_modules/is-plain-obj": { + "node_modules/remark-math/node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", @@ -23961,7 +26280,7 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/remark-gfm/node_modules/trough": { + "node_modules/remark-math/node_modules/trough": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", @@ -23971,7 +26290,7 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/remark-gfm/node_modules/unified": { + "node_modules/remark-math/node_modules/unified": { "version": "10.1.2", "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", @@ -23990,7 +26309,20 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-gfm/node_modules/vfile": { + "node_modules/remark-math/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-math/node_modules/vfile": { "version": "5.3.7", "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", @@ -24006,7 +26338,7 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-gfm/node_modules/vfile-message": { + "node_modules/remark-math/node_modules/vfile-message": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", @@ -24239,6 +26571,43 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark-rehype/node_modules/micromark-util-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", + "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/remark-rehype/node_modules/micromark-util-sanitize-uri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", + "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, "node_modules/remark-rehype/node_modules/trough": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", @@ -24304,6 +26673,19 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark-rehype/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/remark-rehype/node_modules/unist-util-visit": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", @@ -24502,6 +26884,12 @@ "node": ">=0.10.0" } }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -24610,6 +26998,12 @@ "inherits": "^2.0.1" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense" + }, "node_modules/rollup": { "version": "4.40.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz", @@ -24802,13 +27196,12 @@ "license": "MIT" }, "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "node_modules/schema-utils": { @@ -25123,6 +27516,12 @@ "node": ">=8" } }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -25421,7 +27820,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -26082,6 +28480,95 @@ "inline-style-parser": "0.1.1" } }, + "node_modules/styled-components": { + "version": "6.1.19", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.19.tgz", + "integrity": "sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==", + "license": "MIT", + "dependencies": { + "@emotion/is-prop-valid": "1.2.2", + "@emotion/unitless": "0.8.1", + "@types/stylis": "4.2.5", + "css-to-react-native": "3.2.0", + "csstype": "3.1.3", + "postcss": "8.4.49", + "shallowequal": "1.1.0", + "stylis": "4.3.2", + "tslib": "2.6.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + } + }, + "node_modules/styled-components/node_modules/@emotion/is-prop-valid": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", + "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/styled-components/node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==", + "license": "MIT" + }, + "node_modules/styled-components/node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==", + "license": "MIT" + }, + "node_modules/styled-components/node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/styled-components/node_modules/stylis": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", + "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==", + "license": "MIT" + }, + "node_modules/styled-components/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "license": "0BSD" + }, "node_modules/stylis": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", @@ -27187,6 +29674,39 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unist-util-find-after": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-find-after/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/unist-util-find-after/node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unist-util-generated": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.6.tgz", @@ -27248,18 +29768,24 @@ } }, "node_modules/unist-util-stringify-position": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", - "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0" + "@types/unist": "^3.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, + "node_modules/unist-util-stringify-position/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, "node_modules/unist-util-visit": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", @@ -27565,6 +30091,15 @@ "node": ">=0.10.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", + "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", diff --git a/hwproj.front/package.json b/hwproj.front/package.json index 45b6152bb..0ddb05582 100644 --- a/hwproj.front/package.json +++ b/hwproj.front/package.json @@ -15,6 +15,7 @@ "@mui/icons-material": "^5.10.3", "@mui/lab": "^5.0.0-alpha.99", "@mui/material": "^5.16.11", + "@mui/x-charts": "^8.2.0", "@storybook/addon-knobs": "^6.3.0", "@types/bluebird": "^3.5.36", "@types/classnames": "^2.3.1", @@ -25,7 +26,9 @@ "@types/remarkable": "^1.7.4", "@uiw/react-markdown-preview": "4.2.2", "@uiw/react-md-editor": "3.25.6", - "axios": "^0.28.0", + "avatarka": "^1.0.1", + "avatarka-react": "^1.0.1", + "axios": "^0.30.2", "bootstrap": "^4.3.1", "classnames": "^2.3.1", "color-util": "^2.2.3", @@ -40,15 +43,18 @@ "notistack": "^3.0.2", "portable-fetch": "^3.0.0", "qrcode.react": "^4.1.0", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.0.0", + "react-dom": "^18.0.0", + "react-drag-drop-files": "^3.1.0", "react-markdown": "^5.0.0", "react-query": "^3.21.1", "react-router-dom": "^6.5.0", "react-social-login-buttons": "^3.5.1", "react-syntax-highlighter": "^15.5.0", "recharts": "^2.12.3", - "rehype-sanitize": "^6.0.0" + "rehype-katex": "^7.0.1", + "rehype-sanitize": "^6.0.0", + "remark-math": "5.1.1" }, "scripts": { "dev": "npm run type-check && npm run lint && vite", diff --git a/hwproj.front/src/App.tsx b/hwproj.front/src/App.tsx index bd004536e..359f29fa3 100644 --- a/hwproj.front/src/App.tsx +++ b/hwproj.front/src/App.tsx @@ -12,8 +12,6 @@ import TaskSolutionsPage from "./components/Solutions/TaskSolutionsPage"; import {AppBarContextAction, appBarStateManager, Header} from "./components/AppBar"; import Login from "./components/Auth/Login"; import EditCourse from "./components/Courses/EditCourse"; -import EditTask from "./components/Tasks/EditTask"; -import EditHomework from "./components/Homeworks/EditHomework"; import Register from "./components/Auth/Register"; import ExpertsNotebook from "./components/Experts/Notebook"; import StudentSolutionsPage from "./components/Solutions/StudentSolutionsPage"; @@ -118,10 +116,7 @@ class App extends Component<{ navigate: any }, AppState> { }/> }/> }/> - }/> }/> - }/> - }/> }/> }/> diff --git a/hwproj.front/src/api/ApiSingleton.ts b/hwproj.front/src/api/ApiSingleton.ts index 7ee14bbc3..df3527ba0 100644 --- a/hwproj.front/src/api/ApiSingleton.ts +++ b/hwproj.front/src/api/ApiSingleton.ts @@ -57,7 +57,20 @@ class Api { } } -const basePath = import.meta.env.VITE_BASE_PATH +function getApiBase(): string { + const {protocol, hostname, port} = window.location; + + const isLocal = + hostname === "localhost" || + hostname === "127.0.0.1" || + hostname === "::1"; + + const effectivePort = isLocal ? "5000" : (port || ""); + + return `${protocol}//${hostname}${effectivePort ? `:${effectivePort}` : ""}` +} + +const basePath = getApiBase() const authService = new AuthService() let ApiSingleton: Api; diff --git a/hwproj.front/src/api/CustomFilesApi.ts b/hwproj.front/src/api/CustomFilesApi.ts index 79925bf9b..a6e77870b 100644 --- a/hwproj.front/src/api/CustomFilesApi.ts +++ b/hwproj.front/src/api/CustomFilesApi.ts @@ -1,13 +1,26 @@ -import {BaseAPI} from "./api"; +import {BaseAPI, ScopeDTO} from "./api"; +import { IProcessFilesDto } from "../components/Files/IProcessFilesDto"; export default class CustomFilesApi extends BaseAPI { - public uploadFile = async (file: File, courseId: number, homeworkId: number) => { + public processFiles = async (processFilesDto: IProcessFilesDto) => { const formData = new FormData(); - formData.append('file', file); - formData.append('courseId', courseId.toString()); - formData.append('homeworkId', homeworkId.toString()); - const response = await fetch(this.basePath + '/api/Files/upload', { + // Добавляем идентификаторы удаляемых файлов + processFilesDto.deletingFileIds.forEach((fileId) => { + formData.append(`DeletingFileIds`, fileId.toString()); + }); + + // Добавляем новые файлы + processFilesDto.newFiles.forEach((file) => { + formData.append(`NewFiles`, file); + }); + + // Добавляем информацию о области нахождения файлов (Scope) + formData.append('FilesScope.CourseId', processFilesDto.courseId.toString()); + formData.append('FilesScope.CourseUnitType', processFilesDto.courseUnitType.toString()); + formData.append('FilesScope.CourseUnitId', processFilesDto.courseUnitId.toString()); + + const response = await fetch(this.basePath + '/api/Files/process', { method: 'POST', body: formData, headers: { @@ -22,14 +35,12 @@ export default class CustomFilesApi extends BaseAPI { } } - public getDownloadFileLink = async (fileKey: string) => { - // Необходимо, чтобы символы & и др. не влияли на обработку запроса на бэкенде - const encodedFileKey = encodeURIComponent(fileKey); - const response = await fetch(this.basePath + `/api/Files/downloadLink?key=${encodedFileKey}`, { + public getDownloadFileLink = async (fileKey: number) => { + const response = await fetch(this.basePath + `/api/Files/downloadLink?fileId=${fileKey}`, { method: 'GET', headers: { 'Authorization': this.getApiKeyValue(), - }, + } }); if (response.status >= 200 && response.status < 300) { @@ -39,10 +50,8 @@ export default class CustomFilesApi extends BaseAPI { } } - public deleteFileByKey = async (courseId: number, fileKey: string) => { - // Необходимо, чтобы символы & и др. не влияли на обработку запроса на бэкенде - const encodedFileKey = encodeURIComponent(fileKey); - const response = await fetch(this.basePath + `/api/Files?courseId=${courseId}&key=${encodedFileKey}`, { + public deleteFileByKey = async (courseId: number, fileId: number) => { + const response = await fetch(this.basePath + `/api/Files?courseId=${courseId}&key=${fileId}`, { method: 'DELETE', headers: { 'Authorization': this.getApiKeyValue(), @@ -65,4 +74,4 @@ export default class CustomFilesApi extends BaseAPI { ? this.configuration.apiKey('Authorization') : this.configuration.apiKey; } -} \ No newline at end of file +} diff --git a/hwproj.front/src/api/api.ts b/hwproj.front/src/api/api.ts index 0d159fe5b..7a5c048f6 100644 --- a/hwproj.front/src/api/api.ts +++ b/hwproj.front/src/api/api.ts @@ -5,7 +5,7 @@ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) * * OpenAPI spec version: v1 - * + * * * NOTE: This file is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git @@ -78,218 +78,218 @@ export class RequiredError extends Error { } /** - * + * * @export * @interface AccountDataDto */ export interface AccountDataDto { /** - * + * * @type {string} * @memberof AccountDataDto */ userId?: string; /** - * + * * @type {string} * @memberof AccountDataDto */ name?: string; /** - * + * * @type {string} * @memberof AccountDataDto */ surname?: string; /** - * + * * @type {string} * @memberof AccountDataDto */ middleName?: string; /** - * + * * @type {string} * @memberof AccountDataDto */ email?: string; /** - * + * * @type {string} * @memberof AccountDataDto */ role?: string; /** - * + * * @type {boolean} * @memberof AccountDataDto */ isExternalAuth?: boolean; /** - * + * * @type {string} * @memberof AccountDataDto */ githubId?: string; /** - * + * * @type {string} * @memberof AccountDataDto */ bio?: string; /** - * + * * @type {string} * @memberof AccountDataDto */ companyName?: string; } /** - * + * * @export * @interface ActionOptions */ export interface ActionOptions { /** - * + * * @type {boolean} * @memberof ActionOptions */ sendNotification?: boolean; } /** - * + * * @export * @interface AddAnswerForQuestionDto */ export interface AddAnswerForQuestionDto { /** - * + * * @type {number} * @memberof AddAnswerForQuestionDto */ questionId?: number; /** - * + * * @type {string} * @memberof AddAnswerForQuestionDto */ answer?: string; } /** - * + * * @export * @interface AddTaskQuestionDto */ export interface AddTaskQuestionDto { /** - * + * * @type {number} * @memberof AddTaskQuestionDto */ taskId?: number; /** - * + * * @type {string} * @memberof AddTaskQuestionDto */ text?: string; /** - * + * * @type {boolean} * @memberof AddTaskQuestionDto */ isPrivate?: boolean; } /** - * + * * @export * @interface AdvancedCourseStatisticsViewModel */ export interface AdvancedCourseStatisticsViewModel { /** - * + * * @type {CoursePreview} * @memberof AdvancedCourseStatisticsViewModel */ course?: CoursePreview; /** - * + * * @type {Array} * @memberof AdvancedCourseStatisticsViewModel */ homeworks?: Array; /** - * + * * @type {Array} * @memberof AdvancedCourseStatisticsViewModel */ studentStatistics?: Array; /** - * + * * @type {Array} * @memberof AdvancedCourseStatisticsViewModel */ averageStudentSolutions?: Array; /** - * + * * @type {Array} * @memberof AdvancedCourseStatisticsViewModel */ bestStudentSolutions?: Array; } /** - * + * * @export * @interface BooleanResult */ export interface BooleanResult { /** - * + * * @type {boolean} * @memberof BooleanResult */ value?: boolean; /** - * + * * @type {boolean} * @memberof BooleanResult */ succeeded?: boolean; /** - * + * * @type {Array} * @memberof BooleanResult */ errors?: Array; } /** - * + * * @export * @interface CategorizedNotifications */ export interface CategorizedNotifications { /** - * + * * @type {CategoryState} * @memberof CategorizedNotifications */ category?: CategoryState; /** - * + * * @type {Array} * @memberof CategorizedNotifications */ seenNotifications?: Array; /** - * + * * @type {Array} * @memberof CategorizedNotifications */ notSeenNotifications?: Array; } /** - * + * * @export * @enum {string} */ @@ -300,1593 +300,1842 @@ export enum CategoryState { NUMBER_3 = 3 } /** - * + * + * @export + * @interface CourseAllData + */ +export interface CourseAllData { + /** + * + * @type {CourseViewModel} + * @memberof CourseAllData + */ + course?: CourseViewModel; + /** + * + * @type {Array} + * @memberof CourseAllData + */ + assignedStudents?: Array; +} +/** + * * @export * @interface CourseEvents */ export interface CourseEvents { /** - * + * * @type {number} * @memberof CourseEvents */ id?: number; /** - * + * * @type {string} * @memberof CourseEvents */ name?: string; /** - * + * * @type {string} * @memberof CourseEvents */ groupName?: string; /** - * + * * @type {boolean} * @memberof CourseEvents */ isCompleted?: boolean; /** - * + * * @type {number} * @memberof CourseEvents */ newStudentsCount?: number; } /** - * + * * @export * @interface CoursePreview */ export interface CoursePreview { /** - * + * * @type {number} * @memberof CoursePreview */ id?: number; /** - * + * * @type {string} * @memberof CoursePreview */ name?: string; /** - * + * * @type {string} * @memberof CoursePreview */ groupName?: string; /** - * + * * @type {boolean} * @memberof CoursePreview */ isCompleted?: boolean; /** - * + * * @type {Array} * @memberof CoursePreview */ mentorIds?: Array; /** - * + * * @type {number} * @memberof CoursePreview */ taskId?: number; } /** - * + * * @export * @interface CoursePreviewView */ export interface CoursePreviewView { /** - * + * * @type {number} * @memberof CoursePreviewView */ id?: number; /** - * + * * @type {string} * @memberof CoursePreviewView */ name?: string; /** - * + * * @type {string} * @memberof CoursePreviewView */ groupName?: string; /** - * + * * @type {boolean} * @memberof CoursePreviewView */ isCompleted?: boolean; /** - * + * * @type {Array} * @memberof CoursePreviewView */ mentors?: Array; /** - * + * * @type {number} * @memberof CoursePreviewView */ taskId?: number; } /** - * + * * @export * @interface CourseViewModel */ export interface CourseViewModel { /** - * + * * @type {number} * @memberof CourseViewModel */ id?: number; /** - * + * * @type {string} * @memberof CourseViewModel */ name?: string; /** - * + * * @type {string} * @memberof CourseViewModel */ groupName?: string; /** - * + * * @type {boolean} * @memberof CourseViewModel */ isOpen?: boolean; /** - * + * * @type {boolean} * @memberof CourseViewModel */ isCompleted?: boolean; /** - * + * * @type {Array} * @memberof CourseViewModel */ mentors?: Array; /** - * + * * @type {Array} * @memberof CourseViewModel */ acceptedStudents?: Array; /** - * + * * @type {Array} * @memberof CourseViewModel */ newStudents?: Array; /** - * + * * @type {Array} * @memberof CourseViewModel */ homeworks?: Array; } /** - * + * * @export * @interface CreateCourseViewModel */ export interface CreateCourseViewModel { /** - * + * * @type {string} * @memberof CreateCourseViewModel */ name: string; /** - * - * @type {string} + * + * @type {Array} * @memberof CreateCourseViewModel */ - groupName?: string; + groupNames?: Array; /** - * + * * @type {Array} * @memberof CreateCourseViewModel */ studentIDs?: Array; /** - * + * * @type {boolean} * @memberof CreateCourseViewModel */ fetchStudents?: boolean; /** - * + * * @type {boolean} * @memberof CreateCourseViewModel */ isOpen: boolean; /** - * + * * @type {number} * @memberof CreateCourseViewModel */ baseCourseId?: number; } /** - * + * * @export * @interface CreateGroupViewModel */ export interface CreateGroupViewModel { /** - * + * * @type {string} * @memberof CreateGroupViewModel */ name?: string; /** - * + * * @type {Array} * @memberof CreateGroupViewModel */ groupMatesIds: Array; /** - * + * * @type {number} * @memberof CreateGroupViewModel */ courseId: number; } /** - * + * * @export * @interface CreateHomeworkViewModel */ export interface CreateHomeworkViewModel { /** - * + * * @type {string} * @memberof CreateHomeworkViewModel */ title: string; /** - * + * * @type {string} * @memberof CreateHomeworkViewModel */ description?: string; /** - * + * * @type {boolean} * @memberof CreateHomeworkViewModel */ hasDeadline?: boolean; /** - * + * * @type {Date} * @memberof CreateHomeworkViewModel */ deadlineDate?: Date; /** - * + * * @type {boolean} * @memberof CreateHomeworkViewModel */ isDeadlineStrict?: boolean; /** - * + * * @type {Date} * @memberof CreateHomeworkViewModel */ publicationDate?: Date; /** - * + * * @type {boolean} * @memberof CreateHomeworkViewModel */ isGroupWork?: boolean; /** - * + * * @type {Array} * @memberof CreateHomeworkViewModel */ tags?: Array; /** - * - * @type {Array} + * + * @type {Array} * @memberof CreateHomeworkViewModel */ - tasks?: Array; + tasks?: Array; /** - * + * * @type {ActionOptions} * @memberof CreateHomeworkViewModel */ actionOptions?: ActionOptions; } /** - * + * * @export - * @interface CreateTaskViewModel + * @enum {string} */ -export interface CreateTaskViewModel { - /** - * - * @type {string} - * @memberof CreateTaskViewModel - */ - title: string; - /** - * - * @type {string} - * @memberof CreateTaskViewModel - */ - description?: string; - /** - * - * @type {boolean} - * @memberof CreateTaskViewModel - */ - hasDeadline?: boolean; +export enum CriterionType { + NUMBER_0 = 0 +} +/** + * + * @export + * @interface CriterionViewModel + */ +export interface CriterionViewModel { /** - * - * @type {Date} - * @memberof CreateTaskViewModel + * + * @type {number} + * @memberof CriterionViewModel */ - deadlineDate?: Date; + id?: number; /** - * - * @type {boolean} - * @memberof CreateTaskViewModel + * + * @type {CriterionType} + * @memberof CriterionViewModel */ - isDeadlineStrict?: boolean; + type?: CriterionType; /** - * - * @type {Date} - * @memberof CreateTaskViewModel + * + * @type {string} + * @memberof CriterionViewModel */ - publicationDate?: Date; + name: string; /** - * + * * @type {number} - * @memberof CreateTaskViewModel + * @memberof CriterionViewModel */ - maxRating: number; - /** - * - * @type {ActionOptions} - * @memberof CreateTaskViewModel - */ - actionOptions?: ActionOptions; + maxPoints?: number; } /** - * + * * @export * @interface EditAccountViewModel */ export interface EditAccountViewModel { /** - * + * * @type {string} * @memberof EditAccountViewModel */ name: string; /** - * + * * @type {string} * @memberof EditAccountViewModel */ surname: string; /** - * + * * @type {string} * @memberof EditAccountViewModel */ middleName?: string; /** - * + * * @type {string} * @memberof EditAccountViewModel */ email?: string; /** - * + * * @type {string} * @memberof EditAccountViewModel */ bio?: string; /** - * + * * @type {string} * @memberof EditAccountViewModel */ companyName?: string; } /** - * + * * @export * @interface EditMentorWorkspaceDTO */ export interface EditMentorWorkspaceDTO { /** - * + * * @type {Array} * @memberof EditMentorWorkspaceDTO */ studentIds?: Array; /** - * + * * @type {Array} * @memberof EditMentorWorkspaceDTO */ homeworkIds?: Array; } /** - * + * * @export * @interface ExpertDataDTO */ export interface ExpertDataDTO { /** - * + * * @type {string} * @memberof ExpertDataDTO */ id?: string; /** - * + * * @type {string} * @memberof ExpertDataDTO */ name?: string; /** - * + * * @type {string} * @memberof ExpertDataDTO */ surname?: string; /** - * + * * @type {string} * @memberof ExpertDataDTO */ middleName?: string; /** - * + * * @type {string} * @memberof ExpertDataDTO */ email?: string; /** - * + * * @type {string} * @memberof ExpertDataDTO */ bio?: string; /** - * + * * @type {string} * @memberof ExpertDataDTO */ companyName?: string; /** - * + * * @type {Array} * @memberof ExpertDataDTO */ tags?: Array; /** - * + * * @type {string} * @memberof ExpertDataDTO */ lecturerId?: string; } /** - * + * * @export * @interface FileInfoDTO */ export interface FileInfoDTO { /** - * + * + * @type {number} + * @memberof FileInfoDTO + */ + id?: number; + /** + * * @type {string} * @memberof FileInfoDTO */ name?: string; /** - * + * + * @type {string} + * @memberof FileInfoDTO + */ + status?: string; + /** + * * @type {number} * @memberof FileInfoDTO */ - size?: number; + sizeInBytes?: number; /** - * + * * @type {string} * @memberof FileInfoDTO */ - key?: string; + courseUnitType?: string; /** - * + * * @type {number} * @memberof FileInfoDTO */ - homeworkId?: number; + courseUnitId?: number; } /** - * + * * @export - * @interface FilesUploadBody + * @interface FilesProcessBody */ -export interface FilesUploadBody { +export interface FilesProcessBody { /** - * + * * @type {number} - * @memberof FilesUploadBody + * @memberof FilesProcessBody */ - courseId?: number; + filesScopeCourseId?: number; + /** + * + * @type {string} + * @memberof FilesProcessBody + */ + filesScopeCourseUnitType?: string; /** - * + * * @type {number} - * @memberof FilesUploadBody + * @memberof FilesProcessBody */ - homeworkId?: number; + filesScopeCourseUnitId?: number; /** - * - * @type {Blob} - * @memberof FilesUploadBody + * + * @type {Array} + * @memberof FilesProcessBody */ - file: Blob; + deletingFileIds?: Array; + /** + * + * @type {Array} + * @memberof FilesProcessBody + */ + newFiles?: Array; } /** - * + * * @export * @interface GetSolutionModel */ export interface GetSolutionModel { /** - * + * * @type {Date} * @memberof GetSolutionModel */ ratingDate?: Date; /** - * + * * @type {number} * @memberof GetSolutionModel */ id?: number; /** - * + * * @type {string} * @memberof GetSolutionModel */ githubUrl?: string; /** - * + * * @type {string} * @memberof GetSolutionModel */ comment?: string; /** - * + * * @type {SolutionState} * @memberof GetSolutionModel */ state?: SolutionState; /** - * + * * @type {number} * @memberof GetSolutionModel */ rating?: number; /** - * + * * @type {string} * @memberof GetSolutionModel */ studentId?: string; /** - * + * * @type {number} * @memberof GetSolutionModel */ taskId?: number; /** - * + * * @type {Date} * @memberof GetSolutionModel */ publicationDate?: Date; /** - * + * + * @type {boolean} + * @memberof GetSolutionModel + */ + isModified?: boolean; + /** + * * @type {string} * @memberof GetSolutionModel */ lecturerComment?: string; /** - * + * * @type {Array} * @memberof GetSolutionModel */ groupMates?: Array; /** - * + * * @type {AccountDataDto} * @memberof GetSolutionModel */ lecturer?: AccountDataDto; } /** - * + * * @export * @interface GetTaskQuestionDto */ export interface GetTaskQuestionDto { /** - * + * * @type {number} * @memberof GetTaskQuestionDto */ id?: number; /** - * + * * @type {string} * @memberof GetTaskQuestionDto */ studentId?: string; /** - * + * * @type {string} * @memberof GetTaskQuestionDto */ text?: string; /** - * + * * @type {boolean} * @memberof GetTaskQuestionDto */ isPrivate?: boolean; /** - * + * * @type {string} * @memberof GetTaskQuestionDto */ answer?: string; /** - * + * * @type {string} * @memberof GetTaskQuestionDto */ lecturerId?: string; } /** - * + * * @export * @interface GithubCredentials */ export interface GithubCredentials { /** - * + * * @type {string} * @memberof GithubCredentials */ githubId?: string; } /** - * + * * @export * @interface GroupMateViewModel */ export interface GroupMateViewModel { /** - * + * * @type {string} * @memberof GroupMateViewModel */ studentId?: string; } /** - * + * * @export * @interface GroupModel */ export interface GroupModel { /** - * + * * @type {string} * @memberof GroupModel */ groupName?: string; } /** - * + * * @export * @interface GroupViewModel */ export interface GroupViewModel { /** - * + * * @type {number} * @memberof GroupViewModel */ id?: number; /** - * + * * @type {Array} * @memberof GroupViewModel */ studentsIds?: Array; } /** - * + * * @export * @interface HomeworkSolutionsStats */ export interface HomeworkSolutionsStats { /** - * + * * @type {string} * @memberof HomeworkSolutionsStats */ homeworkTitle?: string; /** - * + * * @type {Array} * @memberof HomeworkSolutionsStats */ statsForTasks?: Array; } /** - * + * * @export * @interface HomeworkTaskForEditingViewModel */ export interface HomeworkTaskForEditingViewModel { /** - * + * * @type {HomeworkTaskViewModel} * @memberof HomeworkTaskForEditingViewModel */ task?: HomeworkTaskViewModel; /** - * + * * @type {HomeworkViewModel} * @memberof HomeworkTaskForEditingViewModel */ homework?: HomeworkViewModel; } /** - * + * * @export * @interface HomeworkTaskViewModel */ export interface HomeworkTaskViewModel { /** - * + * * @type {number} * @memberof HomeworkTaskViewModel */ id?: number; /** - * + * * @type {string} * @memberof HomeworkTaskViewModel */ title?: string; /** - * + * * @type {Array} * @memberof HomeworkTaskViewModel */ tags?: Array; /** - * + * * @type {string} * @memberof HomeworkTaskViewModel */ description?: string; /** - * + * * @type {number} * @memberof HomeworkTaskViewModel */ maxRating?: number; /** - * + * * @type {boolean} * @memberof HomeworkTaskViewModel */ hasDeadline?: boolean; /** - * + * * @type {Date} * @memberof HomeworkTaskViewModel */ deadlineDate?: Date; /** - * + * * @type {boolean} * @memberof HomeworkTaskViewModel */ isDeadlineStrict?: boolean; /** - * + * * @type {boolean} * @memberof HomeworkTaskViewModel */ canSendSolution?: boolean; /** - * + * * @type {Date} * @memberof HomeworkTaskViewModel */ publicationDate?: Date; /** - * + * * @type {boolean} * @memberof HomeworkTaskViewModel */ publicationDateNotSet?: boolean; /** - * + * * @type {boolean} * @memberof HomeworkTaskViewModel */ deadlineDateNotSet?: boolean; /** - * + * * @type {number} * @memberof HomeworkTaskViewModel */ homeworkId?: number; /** - * + * * @type {boolean} * @memberof HomeworkTaskViewModel */ isGroupWork?: boolean; /** - * + * * @type {boolean} * @memberof HomeworkTaskViewModel */ isDeferred?: boolean; + /** + * + * @type {Array} + * @memberof HomeworkTaskViewModel + */ + criteria?: Array; } /** - * + * * @export * @interface HomeworkTaskViewModelResult */ export interface HomeworkTaskViewModelResult { /** - * + * * @type {HomeworkTaskViewModel} * @memberof HomeworkTaskViewModelResult */ value?: HomeworkTaskViewModel; /** - * + * * @type {boolean} * @memberof HomeworkTaskViewModelResult */ succeeded?: boolean; /** - * + * * @type {Array} * @memberof HomeworkTaskViewModelResult */ errors?: Array; } /** - * + * * @export * @interface HomeworkUserTaskSolutions */ export interface HomeworkUserTaskSolutions { /** - * + * * @type {string} * @memberof HomeworkUserTaskSolutions */ homeworkTitle?: string; /** - * + * * @type {Array} * @memberof HomeworkUserTaskSolutions */ studentSolutions?: Array; } /** - * + * * @export * @interface HomeworkViewModel */ export interface HomeworkViewModel { /** - * + * * @type {number} * @memberof HomeworkViewModel */ id?: number; /** - * + * * @type {string} * @memberof HomeworkViewModel */ title?: string; /** - * + * * @type {string} * @memberof HomeworkViewModel */ description?: string; /** - * + * * @type {boolean} * @memberof HomeworkViewModel */ hasDeadline?: boolean; /** - * + * * @type {Date} * @memberof HomeworkViewModel */ deadlineDate?: Date; /** - * + * * @type {boolean} * @memberof HomeworkViewModel */ isDeadlineStrict?: boolean; /** - * + * * @type {Date} * @memberof HomeworkViewModel */ publicationDate?: Date; /** - * + * * @type {boolean} * @memberof HomeworkViewModel */ publicationDateNotSet?: boolean; /** - * + * * @type {boolean} * @memberof HomeworkViewModel */ deadlineDateNotSet?: boolean; /** - * + * * @type {number} * @memberof HomeworkViewModel */ courseId?: number; /** - * + * * @type {boolean} * @memberof HomeworkViewModel */ isDeferred?: boolean; /** - * + * * @type {boolean} * @memberof HomeworkViewModel */ isGroupWork?: boolean; /** - * + * * @type {Array} * @memberof HomeworkViewModel */ tags?: Array; /** - * + * * @type {Array} * @memberof HomeworkViewModel */ tasks?: Array; } /** - * + * * @export * @interface HomeworkViewModelResult */ export interface HomeworkViewModelResult { /** - * + * * @type {HomeworkViewModel} * @memberof HomeworkViewModelResult */ value?: HomeworkViewModel; /** - * + * * @type {boolean} * @memberof HomeworkViewModelResult */ succeeded?: boolean; /** - * + * * @type {Array} * @memberof HomeworkViewModelResult */ errors?: Array; } /** - * + * * @export * @interface HomeworksGroupSolutionStats */ export interface HomeworksGroupSolutionStats { /** - * + * * @type {string} * @memberof HomeworksGroupSolutionStats */ groupTitle?: string; /** - * + * * @type {Array} * @memberof HomeworksGroupSolutionStats */ statsForHomeworks?: Array; } /** - * + * * @export * @interface HomeworksGroupUserTaskSolutions */ export interface HomeworksGroupUserTaskSolutions { /** - * + * * @type {string} * @memberof HomeworksGroupUserTaskSolutions */ groupTitle?: string; /** - * + * * @type {Array} * @memberof HomeworksGroupUserTaskSolutions */ homeworkSolutions?: Array; } /** - * + * * @export * @interface InviteExpertViewModel */ export interface InviteExpertViewModel { /** - * + * * @type {string} * @memberof InviteExpertViewModel */ userId?: string; /** - * + * * @type {string} * @memberof InviteExpertViewModel */ userEmail?: string; /** - * + * * @type {number} * @memberof InviteExpertViewModel */ courseId?: number; /** - * + * * @type {Array} * @memberof InviteExpertViewModel */ studentIds?: Array; /** - * + * * @type {Array} * @memberof InviteExpertViewModel */ homeworkIds?: Array; } /** - * + * * @export * @interface InviteLecturerViewModel */ export interface InviteLecturerViewModel { /** - * + * * @type {string} * @memberof InviteLecturerViewModel */ email: string; } /** - * + * * @export * @interface LoginViewModel */ export interface LoginViewModel { /** - * + * * @type {string} * @memberof LoginViewModel */ email: string; /** - * + * * @type {string} * @memberof LoginViewModel */ password: string; /** - * + * * @type {boolean} * @memberof LoginViewModel */ rememberMe: boolean; } /** - * + * + * @export + * @interface MentorToAssignedStudentsDTO + */ +export interface MentorToAssignedStudentsDTO { + /** + * + * @type {string} + * @memberof MentorToAssignedStudentsDTO + */ + mentorId?: string; + /** + * + * @type {Array} + * @memberof MentorToAssignedStudentsDTO + */ + selectedStudentsIds?: Array; +} +/** + * * @export * @interface NotificationViewModel */ export interface NotificationViewModel { /** - * + * * @type {number} * @memberof NotificationViewModel */ id?: number; /** - * + * * @type {string} * @memberof NotificationViewModel */ sender?: string; /** - * + * * @type {string} * @memberof NotificationViewModel */ owner?: string; /** - * + * * @type {CategoryState} * @memberof NotificationViewModel */ category?: CategoryState; /** - * + * * @type {string} * @memberof NotificationViewModel */ body?: string; /** - * + * * @type {boolean} * @memberof NotificationViewModel */ hasSeen?: boolean; /** - * + * * @type {Date} * @memberof NotificationViewModel */ date?: Date; } /** - * + * * @export * @interface NotificationsSettingDto */ export interface NotificationsSettingDto { /** - * + * * @type {string} * @memberof NotificationsSettingDto */ category?: string; /** - * + * * @type {boolean} * @memberof NotificationsSettingDto */ isEnabled?: boolean; } /** - * + * + * @export + * @interface PostAutomatedSolutionModel + */ +export interface PostAutomatedSolutionModel { + /** + * + * @type {string} + * @memberof PostAutomatedSolutionModel + */ + taskId: string; + /** + * + * @type {TaskIdType} + * @memberof PostAutomatedSolutionModel + */ + taskIdType?: TaskIdType; + /** + * + * @type {string} + * @memberof PostAutomatedSolutionModel + */ + studentId: string; + /** + * + * @type {StudentIdType} + * @memberof PostAutomatedSolutionModel + */ + studentIdType?: StudentIdType; + /** + * + * @type {string} + * @memberof PostAutomatedSolutionModel + */ + githubUrl?: string; + /** + * + * @type {string} + * @memberof PostAutomatedSolutionModel + */ + comment?: string; +} +/** + * + * @export + * @interface PostSolutionModel + */ +export interface PostSolutionModel { + /** + * + * @type {string} + * @memberof PostSolutionModel + */ + githubUrl?: string; + /** + * + * @type {string} + * @memberof PostSolutionModel + */ + comment?: string; + /** + * + * @type {Array} + * @memberof PostSolutionModel + */ + groupMateIds?: Array; +} +/** + * + * @export + * @interface PostTaskViewModel + */ +export interface PostTaskViewModel { + /** + * + * @type {string} + * @memberof PostTaskViewModel + */ + title: string; + /** + * + * @type {string} + * @memberof PostTaskViewModel + */ + description?: string; + /** + * + * @type {boolean} + * @memberof PostTaskViewModel + */ + hasDeadline?: boolean; + /** + * + * @type {Date} + * @memberof PostTaskViewModel + */ + deadlineDate?: Date; + /** + * + * @type {boolean} + * @memberof PostTaskViewModel + */ + isDeadlineStrict?: boolean; + /** + * + * @type {Date} + * @memberof PostTaskViewModel + */ + publicationDate?: Date; + /** + * + * @type {number} + * @memberof PostTaskViewModel + */ + maxRating: number; + /** + * + * @type {ActionOptions} + * @memberof PostTaskViewModel + */ + actionOptions?: ActionOptions; + /** + * + * @type {Array} + * @memberof PostTaskViewModel + */ + criteria?: Array; +} +/** + * * @export * @interface ProgramModel */ export interface ProgramModel { /** - * + * * @type {string} * @memberof ProgramModel */ programName?: string; } /** - * + * + * @export + * @interface QuestionsSummary + */ +export interface QuestionsSummary { + /** + * + * @type {number} + * @memberof QuestionsSummary + */ + taskId?: number; + /** + * + * @type {string} + * @memberof QuestionsSummary + */ + taskTitle?: string; + /** + * + * @type {number} + * @memberof QuestionsSummary + */ + count?: number; +} +/** + * * @export * @interface RateSolutionModel */ export interface RateSolutionModel { /** - * + * * @type {number} * @memberof RateSolutionModel */ rating?: number; /** - * + * * @type {string} * @memberof RateSolutionModel */ lecturerComment?: string; } /** - * + * * @export * @interface RegisterExpertViewModel */ export interface RegisterExpertViewModel { /** - * + * * @type {string} * @memberof RegisterExpertViewModel */ name: string; /** - * + * * @type {string} * @memberof RegisterExpertViewModel */ surname: string; /** - * + * * @type {string} * @memberof RegisterExpertViewModel */ middleName?: string; /** - * + * * @type {string} * @memberof RegisterExpertViewModel */ email: string; /** - * + * * @type {string} * @memberof RegisterExpertViewModel */ bio?: string; /** - * + * * @type {string} * @memberof RegisterExpertViewModel */ companyName?: string; /** - * + * * @type {Array} * @memberof RegisterExpertViewModel */ tags?: Array; } /** - * + * * @export * @interface RegisterViewModel */ export interface RegisterViewModel { /** - * + * * @type {string} * @memberof RegisterViewModel */ name: string; /** - * + * * @type {string} * @memberof RegisterViewModel */ surname: string; /** - * + * * @type {string} * @memberof RegisterViewModel */ middleName?: string; /** - * + * * @type {string} * @memberof RegisterViewModel */ email: string; } /** - * + * * @export * @interface RequestPasswordRecoveryViewModel */ export interface RequestPasswordRecoveryViewModel { /** - * + * * @type {string} * @memberof RequestPasswordRecoveryViewModel */ email: string; } /** - * + * * @export * @interface ResetPasswordViewModel */ export interface ResetPasswordViewModel { /** - * + * * @type {string} * @memberof ResetPasswordViewModel */ userId: string; /** - * + * * @type {string} * @memberof ResetPasswordViewModel */ token: string; /** - * + * * @type {string} * @memberof ResetPasswordViewModel */ password: string; /** - * + * * @type {string} * @memberof ResetPasswordViewModel */ passwordConfirm: string; } /** - * + * * @export * @interface Result */ export interface Result { /** - * + * * @type {boolean} * @memberof Result */ succeeded?: boolean; /** - * + * * @type {Array} * @memberof Result */ errors?: Array; } /** - * + * + * @export + * @interface ScopeDTO + */ +export interface ScopeDTO { + /** + * + * @type {number} + * @memberof ScopeDTO + */ + courseId?: number; + /** + * + * @type {string} + * @memberof ScopeDTO + */ + courseUnitType?: string; + /** + * + * @type {number} + * @memberof ScopeDTO + */ + courseUnitId?: number; +} +/** + * * @export * @interface Solution */ export interface Solution { /** - * + * * @type {number} * @memberof Solution */ id?: number; /** - * + * * @type {string} * @memberof Solution */ githubUrl?: string; /** - * + * * @type {string} * @memberof Solution */ comment?: string; /** - * + * * @type {SolutionState} * @memberof Solution */ state?: SolutionState; /** - * + * * @type {number} * @memberof Solution */ rating?: number; /** - * + * * @type {string} * @memberof Solution */ studentId?: string; /** - * + * * @type {string} * @memberof Solution */ lecturerId?: string; /** - * + * * @type {number} * @memberof Solution */ groupId?: number; /** - * + * * @type {number} * @memberof Solution */ taskId?: number; /** - * + * * @type {Date} * @memberof Solution */ publicationDate?: Date; /** - * + * + * @type {boolean} + * @memberof Solution + */ + isModified?: boolean; + /** + * * @type {Date} * @memberof Solution */ ratingDate?: Date; /** - * + * * @type {string} * @memberof Solution */ lecturerComment?: string; } /** - * + * * @export * @interface SolutionActualityDto */ export interface SolutionActualityDto { /** - * + * * @type {SolutionActualityPart} * @memberof SolutionActualityDto */ commitsActuality?: SolutionActualityPart; /** - * + * * @type {SolutionActualityPart} * @memberof SolutionActualityDto */ testsActuality?: SolutionActualityPart; } /** - * + * * @export * @interface SolutionActualityPart */ export interface SolutionActualityPart { /** - * + * * @type {boolean} * @memberof SolutionActualityPart */ isActual?: boolean; /** - * + * * @type {string} * @memberof SolutionActualityPart */ comment?: string; /** - * + * * @type {string} * @memberof SolutionActualityPart */ additionalData?: string; } /** - * + * * @export * @interface SolutionPreviewView */ export interface SolutionPreviewView { /** - * + * * @type {number} * @memberof SolutionPreviewView */ solutionId?: number; /** - * + * * @type {AccountDataDto} * @memberof SolutionPreviewView */ student?: AccountDataDto; /** - * + * * @type {string} * @memberof SolutionPreviewView */ courseTitle?: string; /** - * + * * @type {number} * @memberof SolutionPreviewView */ courseId?: number; /** - * + * * @type {string} * @memberof SolutionPreviewView */ homeworkTitle?: string; /** - * + * * @type {string} * @memberof SolutionPreviewView */ taskTitle?: string; /** - * + * * @type {number} * @memberof SolutionPreviewView */ taskId?: number; /** - * + * * @type {Date} * @memberof SolutionPreviewView */ publicationDate?: Date; /** - * + * * @type {number} * @memberof SolutionPreviewView */ groupId?: number; /** - * + * * @type {boolean} * @memberof SolutionPreviewView */ isFirstTry?: boolean; /** - * + * * @type {boolean} * @memberof SolutionPreviewView */ sentAfterDeadline?: boolean; /** - * + * * @type {boolean} * @memberof SolutionPreviewView */ isCourseCompleted?: boolean; + /** + * + * @type {boolean} + * @memberof SolutionPreviewView + */ + isTest?: boolean; } /** - * + * * @export * @enum {string} */ @@ -1896,728 +2145,759 @@ export enum SolutionState { NUMBER_2 = 2 } /** - * + * * @export * @interface SolutionViewModel */ export interface SolutionViewModel { /** - * + * * @type {string} * @memberof SolutionViewModel */ githubUrl?: string; /** - * + * * @type {string} * @memberof SolutionViewModel */ comment?: string; /** - * + * * @type {string} * @memberof SolutionViewModel */ studentId?: string; /** - * + * * @type {Array} * @memberof SolutionViewModel */ groupMateIds?: Array; /** - * + * * @type {Date} * @memberof SolutionViewModel */ publicationDate?: Date; /** - * + * * @type {string} * @memberof SolutionViewModel */ lecturerComment?: string; /** - * + * * @type {number} * @memberof SolutionViewModel */ rating?: number; /** - * + * * @type {Date} * @memberof SolutionViewModel */ ratingDate?: Date; } /** - * + * * @export * @interface StatisticsCourseHomeworksModel */ export interface StatisticsCourseHomeworksModel { /** - * + * * @type {number} * @memberof StatisticsCourseHomeworksModel */ id?: number; /** - * + * * @type {Array} * @memberof StatisticsCourseHomeworksModel */ tasks?: Array; } /** - * + * * @export * @interface StatisticsCourseMatesModel */ export interface StatisticsCourseMatesModel { /** - * + * * @type {string} * @memberof StatisticsCourseMatesModel */ id?: string; /** - * + * * @type {string} * @memberof StatisticsCourseMatesModel */ name?: string; /** - * + * * @type {string} * @memberof StatisticsCourseMatesModel */ surname?: string; /** - * + * * @type {Array} * @memberof StatisticsCourseMatesModel */ reviewers?: Array; /** - * + * * @type {Array} * @memberof StatisticsCourseMatesModel */ homeworks?: Array; } /** - * + * * @export * @interface StatisticsCourseMeasureSolutionModel */ export interface StatisticsCourseMeasureSolutionModel { /** - * + * * @type {number} * @memberof StatisticsCourseMeasureSolutionModel */ rating?: number; /** - * + * * @type {number} * @memberof StatisticsCourseMeasureSolutionModel */ taskId?: number; /** - * + * * @type {Date} * @memberof StatisticsCourseMeasureSolutionModel */ publicationDate?: Date; } /** - * + * * @export * @interface StatisticsCourseTasksModel */ export interface StatisticsCourseTasksModel { /** - * + * * @type {number} * @memberof StatisticsCourseTasksModel */ id?: number; /** - * + * * @type {Array} * @memberof StatisticsCourseTasksModel */ solution?: Array; } /** - * + * * @export * @interface StatisticsLecturersModel */ export interface StatisticsLecturersModel { /** - * + * * @type {AccountDataDto} * @memberof StatisticsLecturersModel */ lecturer?: AccountDataDto; /** - * + * * @type {number} * @memberof StatisticsLecturersModel */ numberOfCheckedSolutions?: number; /** - * + * * @type {number} * @memberof StatisticsLecturersModel */ numberOfCheckedUniqueSolutions?: number; } /** - * + * * @export * @interface StudentCharacteristicsDto */ export interface StudentCharacteristicsDto { /** - * + * * @type {Array} * @memberof StudentCharacteristicsDto */ tags?: Array; /** - * + * * @type {string} * @memberof StudentCharacteristicsDto */ description?: string; } /** - * + * * @export * @interface StudentDataDto */ export interface StudentDataDto { /** - * - * @type {StudentCharacteristicsDto} - * @memberof StudentDataDto - */ - characteristics?: StudentCharacteristicsDto; - /** - * + * * @type {string} * @memberof StudentDataDto */ userId?: string; /** - * + * * @type {string} * @memberof StudentDataDto */ name?: string; /** - * + * * @type {string} * @memberof StudentDataDto */ surname?: string; /** - * + * * @type {string} * @memberof StudentDataDto */ middleName?: string; /** - * + * * @type {string} * @memberof StudentDataDto */ email?: string; /** - * + * * @type {string} * @memberof StudentDataDto */ role?: string; /** - * + * * @type {boolean} * @memberof StudentDataDto */ isExternalAuth?: boolean; /** - * + * * @type {string} * @memberof StudentDataDto */ githubId?: string; /** - * + * * @type {string} * @memberof StudentDataDto */ bio?: string; /** - * + * * @type {string} * @memberof StudentDataDto */ companyName?: string; + /** + * + * @type {StudentCharacteristicsDto} + * @memberof StudentDataDto + */ + characteristics?: StudentCharacteristicsDto; } /** - * + * + * @export + * @enum {string} + */ +export enum StudentIdType { + NUMBER_0 = 0, + NUMBER_1 = 1, + NUMBER_2 = 2 +} +/** + * * @export * @interface SystemInfo */ export interface SystemInfo { /** - * + * * @type {string} * @memberof SystemInfo */ service?: string; /** - * + * * @type {boolean} * @memberof SystemInfo */ isAvailable?: boolean; } /** - * + * * @export * @interface TaskDeadlineDto */ export interface TaskDeadlineDto { /** - * + * * @type {number} * @memberof TaskDeadlineDto */ taskId?: number; /** - * + * * @type {Array} * @memberof TaskDeadlineDto */ tags?: Array; /** - * + * * @type {string} * @memberof TaskDeadlineDto */ taskTitle?: string; /** - * + * * @type {string} * @memberof TaskDeadlineDto */ courseTitle?: string; /** - * + * * @type {number} * @memberof TaskDeadlineDto */ courseId?: number; /** - * + * * @type {number} * @memberof TaskDeadlineDto */ homeworkId?: number; /** - * + * * @type {number} * @memberof TaskDeadlineDto */ maxRating?: number; /** - * + * * @type {Date} * @memberof TaskDeadlineDto */ publicationDate?: Date; /** - * + * * @type {Date} * @memberof TaskDeadlineDto */ deadlineDate?: Date; } /** - * + * * @export * @interface TaskDeadlineView */ export interface TaskDeadlineView { /** - * + * * @type {TaskDeadlineDto} * @memberof TaskDeadlineView */ deadline?: TaskDeadlineDto; /** - * + * * @type {SolutionState} * @memberof TaskDeadlineView */ solutionState?: SolutionState; /** - * + * * @type {number} * @memberof TaskDeadlineView */ rating?: number; /** - * + * * @type {number} * @memberof TaskDeadlineView */ maxRating?: number; /** - * + * * @type {boolean} * @memberof TaskDeadlineView */ deadlinePast?: boolean; } /** - * + * + * @export + * @enum {string} + */ +export enum TaskIdType { + NUMBER_0 = 0, + NUMBER_1 = 1 +} +/** + * * @export * @interface TaskSolutionStatisticsPageData */ export interface TaskSolutionStatisticsPageData { /** - * + * + * @type {Array} + * @memberof TaskSolutionStatisticsPageData + */ + courseMentors?: Array; + /** + * * @type {Array} * @memberof TaskSolutionStatisticsPageData */ taskSolutions?: Array; /** - * + * * @type {number} * @memberof TaskSolutionStatisticsPageData */ courseId?: number; /** - * + * * @type {Array} * @memberof TaskSolutionStatisticsPageData */ statsForTasks?: Array; } /** - * + * * @export * @interface TaskSolutions */ export interface TaskSolutions { /** - * + * * @type {number} * @memberof TaskSolutions */ taskId?: number; /** - * + * * @type {Array} * @memberof TaskSolutions */ studentSolutions?: Array; } /** - * + * * @export * @interface TaskSolutionsStats */ export interface TaskSolutionsStats { /** - * + * * @type {number} * @memberof TaskSolutionsStats */ taskId?: number; /** - * + * * @type {number} * @memberof TaskSolutionsStats */ countUnratedSolutions?: number; /** - * + * * @type {string} * @memberof TaskSolutionsStats */ title?: string; /** - * + * * @type {Array} * @memberof TaskSolutionsStats */ tags?: Array; } /** - * + * * @export * @interface TokenCredentials */ export interface TokenCredentials { /** - * + * * @type {string} * @memberof TokenCredentials */ accessToken?: string; } /** - * + * * @export * @interface TokenCredentialsResult */ export interface TokenCredentialsResult { /** - * + * * @type {TokenCredentials} * @memberof TokenCredentialsResult */ value?: TokenCredentials; /** - * + * * @type {boolean} * @memberof TokenCredentialsResult */ succeeded?: boolean; /** - * + * * @type {Array} * @memberof TokenCredentialsResult */ errors?: Array; } /** - * + * * @export * @interface UnratedSolutionPreviews */ export interface UnratedSolutionPreviews { /** - * + * * @type {Array} * @memberof UnratedSolutionPreviews */ unratedSolutions?: Array; } /** - * + * * @export * @interface UpdateCourseViewModel */ export interface UpdateCourseViewModel { /** - * + * * @type {string} * @memberof UpdateCourseViewModel */ name: string; /** - * + * * @type {string} * @memberof UpdateCourseViewModel */ groupName?: string; /** - * + * * @type {boolean} * @memberof UpdateCourseViewModel */ isOpen: boolean; /** - * + * * @type {boolean} * @memberof UpdateCourseViewModel */ isCompleted?: boolean; } /** - * + * * @export * @interface UpdateExpertTagsDTO */ export interface UpdateExpertTagsDTO { /** - * + * * @type {string} * @memberof UpdateExpertTagsDTO */ expertId?: string; /** - * + * * @type {Array} * @memberof UpdateExpertTagsDTO */ tags?: Array; } /** - * + * * @export * @interface UpdateGroupViewModel */ export interface UpdateGroupViewModel { /** - * + * * @type {string} * @memberof UpdateGroupViewModel */ name?: string; /** - * + * * @type {Array} * @memberof UpdateGroupViewModel */ tasks?: Array; /** - * + * * @type {Array} * @memberof UpdateGroupViewModel */ groupMates?: Array; } /** - * + * * @export * @interface UrlDto */ export interface UrlDto { /** - * + * * @type {string} * @memberof UrlDto */ url?: string; } /** - * + * * @export * @interface UserDataDto */ export interface UserDataDto { /** - * + * * @type {AccountDataDto} * @memberof UserDataDto */ userData?: AccountDataDto; /** - * + * * @type {Array} * @memberof UserDataDto */ courseEvents?: Array; /** - * + * * @type {Array} * @memberof UserDataDto */ taskDeadlines?: Array; } /** - * + * * @export * @interface UserTaskSolutions */ export interface UserTaskSolutions { /** - * + * * @type {Array} * @memberof UserTaskSolutions */ solutions?: Array; /** - * + * * @type {StudentDataDto} * @memberof UserTaskSolutions */ student?: StudentDataDto; + /** + * + * @type {boolean} + * @memberof UserTaskSolutions + */ + hasDifferentReviewer?: boolean; } /** - * + * * @export * @interface UserTaskSolutions2 */ export interface UserTaskSolutions2 { /** - * + * * @type {number} * @memberof UserTaskSolutions2 */ maxRating?: number; /** - * + * * @type {string} * @memberof UserTaskSolutions2 */ title?: string; /** - * + * * @type {Array} * @memberof UserTaskSolutions2 */ tags?: Array; /** - * + * * @type {string} * @memberof UserTaskSolutions2 */ taskId?: string; /** - * + * * @type {Array} * @memberof UserTaskSolutions2 */ solutions?: Array; } /** - * + * * @export * @interface UserTaskSolutionsPageData */ export interface UserTaskSolutionsPageData { /** - * + * * @type {number} * @memberof UserTaskSolutionsPageData */ courseId?: number; /** - * + * * @type {Array} * @memberof UserTaskSolutionsPageData */ courseMates?: Array; /** - * + * * @type {Array} * @memberof UserTaskSolutionsPageData */ taskSolutions?: Array; } /** - * + * * @export * @interface WorkspaceViewModel */ export interface WorkspaceViewModel { /** - * + * * @type {Array} * @memberof WorkspaceViewModel */ students?: Array; /** - * + * * @type {Array} * @memberof WorkspaceViewModel */ @@ -2630,8 +2910,8 @@ export interface WorkspaceViewModel { export const AccountApiFetchParamCreator = function (configuration?: Configuration) { return { /** - * - * @param {string} [code] + * + * @param {string} [code] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -2645,8 +2925,8 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -2665,8 +2945,8 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {EditAccountViewModel} [body] + * + * @param {EditAccountViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -2680,12 +2960,12 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -2700,7 +2980,7 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -2714,8 +2994,8 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -2730,8 +3010,8 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {UrlDto} [body] + * + * @param {UrlDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -2745,12 +3025,12 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -2765,7 +3045,7 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -2779,8 +3059,8 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -2795,8 +3075,8 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {string} userId + * + * @param {string} userId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -2815,8 +3095,8 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -2831,8 +3111,8 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {InviteLecturerViewModel} [body] + * + * @param {InviteLecturerViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -2846,12 +3126,12 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -2866,8 +3146,8 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {LoginViewModel} [body] + * + * @param {LoginViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -2881,12 +3161,12 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -2901,7 +3181,7 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -2915,8 +3195,8 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -2931,8 +3211,8 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {RegisterViewModel} [body] + * + * @param {RegisterViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -2946,12 +3226,12 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -2966,8 +3246,8 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {RequestPasswordRecoveryViewModel} [body] + * + * @param {RequestPasswordRecoveryViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -2981,12 +3261,12 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -3001,8 +3281,8 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {ResetPasswordViewModel} [body] + * + * @param {ResetPasswordViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3016,12 +3296,12 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -3045,8 +3325,8 @@ export const AccountApiFetchParamCreator = function (configuration?: Configurati export const AccountApiFp = function(configuration?: Configuration) { return { /** - * - * @param {string} [code] + * + * @param {string} [code] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3063,8 +3343,8 @@ export const AccountApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {EditAccountViewModel} [body] + * + * @param {EditAccountViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3081,7 +3361,7 @@ export const AccountApiFp = function(configuration?: Configuration) { }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3098,8 +3378,8 @@ export const AccountApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {UrlDto} [body] + * + * @param {UrlDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3116,7 +3396,7 @@ export const AccountApiFp = function(configuration?: Configuration) { }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3133,8 +3413,8 @@ export const AccountApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {string} userId + * + * @param {string} userId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3151,8 +3431,8 @@ export const AccountApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {InviteLecturerViewModel} [body] + * + * @param {InviteLecturerViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3169,8 +3449,8 @@ export const AccountApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {LoginViewModel} [body] + * + * @param {LoginViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3187,7 +3467,7 @@ export const AccountApiFp = function(configuration?: Configuration) { }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3204,8 +3484,8 @@ export const AccountApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {RegisterViewModel} [body] + * + * @param {RegisterViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3222,8 +3502,8 @@ export const AccountApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {RequestPasswordRecoveryViewModel} [body] + * + * @param {RequestPasswordRecoveryViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3240,8 +3520,8 @@ export const AccountApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {ResetPasswordViewModel} [body] + * + * @param {ResetPasswordViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3267,8 +3547,8 @@ export const AccountApiFp = function(configuration?: Configuration) { export const AccountApiFactory = function (configuration?: Configuration, fetch?: FetchAPI, basePath?: string) { return { /** - * - * @param {string} [code] + * + * @param {string} [code] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3276,8 +3556,8 @@ export const AccountApiFactory = function (configuration?: Configuration, fetch? return AccountApiFp(configuration).accountAuthorizeGithub(code, options)(fetch, basePath); }, /** - * - * @param {EditAccountViewModel} [body] + * + * @param {EditAccountViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3285,7 +3565,7 @@ export const AccountApiFactory = function (configuration?: Configuration, fetch? return AccountApiFp(configuration).accountEdit(body, options)(fetch, basePath); }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3293,8 +3573,8 @@ export const AccountApiFactory = function (configuration?: Configuration, fetch? return AccountApiFp(configuration).accountGetAllStudents(options)(fetch, basePath); }, /** - * - * @param {UrlDto} [body] + * + * @param {UrlDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3302,7 +3582,7 @@ export const AccountApiFactory = function (configuration?: Configuration, fetch? return AccountApiFp(configuration).accountGetGithubLoginUrl(body, options)(fetch, basePath); }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3310,8 +3590,8 @@ export const AccountApiFactory = function (configuration?: Configuration, fetch? return AccountApiFp(configuration).accountGetUserData(options)(fetch, basePath); }, /** - * - * @param {string} userId + * + * @param {string} userId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3319,8 +3599,8 @@ export const AccountApiFactory = function (configuration?: Configuration, fetch? return AccountApiFp(configuration).accountGetUserDataById(userId, options)(fetch, basePath); }, /** - * - * @param {InviteLecturerViewModel} [body] + * + * @param {InviteLecturerViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3328,8 +3608,8 @@ export const AccountApiFactory = function (configuration?: Configuration, fetch? return AccountApiFp(configuration).accountInviteNewLecturer(body, options)(fetch, basePath); }, /** - * - * @param {LoginViewModel} [body] + * + * @param {LoginViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3337,7 +3617,7 @@ export const AccountApiFactory = function (configuration?: Configuration, fetch? return AccountApiFp(configuration).accountLogin(body, options)(fetch, basePath); }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3345,8 +3625,8 @@ export const AccountApiFactory = function (configuration?: Configuration, fetch? return AccountApiFp(configuration).accountRefreshToken(options)(fetch, basePath); }, /** - * - * @param {RegisterViewModel} [body] + * + * @param {RegisterViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3354,8 +3634,8 @@ export const AccountApiFactory = function (configuration?: Configuration, fetch? return AccountApiFp(configuration).accountRegister(body, options)(fetch, basePath); }, /** - * - * @param {RequestPasswordRecoveryViewModel} [body] + * + * @param {RequestPasswordRecoveryViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3363,8 +3643,8 @@ export const AccountApiFactory = function (configuration?: Configuration, fetch? return AccountApiFp(configuration).accountRequestPasswordRecovery(body, options)(fetch, basePath); }, /** - * - * @param {ResetPasswordViewModel} [body] + * + * @param {ResetPasswordViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3382,8 +3662,8 @@ export const AccountApiFactory = function (configuration?: Configuration, fetch? */ export class AccountApi extends BaseAPI { /** - * - * @param {string} [code] + * + * @param {string} [code] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AccountApi @@ -3393,8 +3673,8 @@ export class AccountApi extends BaseAPI { } /** - * - * @param {EditAccountViewModel} [body] + * + * @param {EditAccountViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AccountApi @@ -3404,7 +3684,7 @@ export class AccountApi extends BaseAPI { } /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AccountApi @@ -3414,8 +3694,8 @@ export class AccountApi extends BaseAPI { } /** - * - * @param {UrlDto} [body] + * + * @param {UrlDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AccountApi @@ -3425,7 +3705,7 @@ export class AccountApi extends BaseAPI { } /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AccountApi @@ -3435,8 +3715,8 @@ export class AccountApi extends BaseAPI { } /** - * - * @param {string} userId + * + * @param {string} userId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AccountApi @@ -3446,8 +3726,8 @@ export class AccountApi extends BaseAPI { } /** - * - * @param {InviteLecturerViewModel} [body] + * + * @param {InviteLecturerViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AccountApi @@ -3457,8 +3737,8 @@ export class AccountApi extends BaseAPI { } /** - * - * @param {LoginViewModel} [body] + * + * @param {LoginViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AccountApi @@ -3468,7 +3748,7 @@ export class AccountApi extends BaseAPI { } /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AccountApi @@ -3478,8 +3758,8 @@ export class AccountApi extends BaseAPI { } /** - * - * @param {RegisterViewModel} [body] + * + * @param {RegisterViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AccountApi @@ -3489,8 +3769,8 @@ export class AccountApi extends BaseAPI { } /** - * - * @param {RequestPasswordRecoveryViewModel} [body] + * + * @param {RequestPasswordRecoveryViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AccountApi @@ -3500,8 +3780,8 @@ export class AccountApi extends BaseAPI { } /** - * - * @param {ResetPasswordViewModel} [body] + * + * @param {ResetPasswordViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof AccountApi @@ -3518,10 +3798,10 @@ export class AccountApi extends BaseAPI { export const CourseGroupsApiFetchParamCreator = function (configuration?: Configuration) { return { /** - * - * @param {number} courseId - * @param {number} groupId - * @param {string} [userId] + * + * @param {number} courseId + * @param {number} groupId + * @param {string} [userId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3545,8 +3825,8 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -3565,9 +3845,9 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config }; }, /** - * - * @param {number} courseId - * @param {CreateGroupViewModel} [body] + * + * @param {number} courseId + * @param {CreateGroupViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3586,12 +3866,12 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -3606,9 +3886,9 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config }; }, /** - * - * @param {number} courseId - * @param {number} groupId + * + * @param {number} courseId + * @param {number} groupId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3632,8 +3912,8 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -3648,8 +3928,8 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3668,8 +3948,8 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -3684,8 +3964,8 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3704,8 +3984,8 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -3720,8 +4000,8 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config }; }, /** - * - * @param {number} groupId + * + * @param {number} groupId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3740,8 +4020,8 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -3756,8 +4036,8 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config }; }, /** - * - * @param {number} groupId + * + * @param {number} groupId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3776,8 +4056,8 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -3792,10 +4072,10 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config }; }, /** - * - * @param {number} courseId - * @param {number} groupId - * @param {string} [userId] + * + * @param {number} courseId + * @param {number} groupId + * @param {string} [userId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3819,8 +4099,8 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -3839,10 +4119,10 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config }; }, /** - * - * @param {number} courseId - * @param {number} groupId - * @param {UpdateGroupViewModel} [body] + * + * @param {number} courseId + * @param {number} groupId + * @param {UpdateGroupViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3866,12 +4146,12 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -3895,10 +4175,10 @@ export const CourseGroupsApiFetchParamCreator = function (configuration?: Config export const CourseGroupsApiFp = function(configuration?: Configuration) { return { /** - * - * @param {number} courseId - * @param {number} groupId - * @param {string} [userId] + * + * @param {number} courseId + * @param {number} groupId + * @param {string} [userId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3915,9 +4195,9 @@ export const CourseGroupsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId - * @param {CreateGroupViewModel} [body] + * + * @param {number} courseId + * @param {CreateGroupViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3934,9 +4214,9 @@ export const CourseGroupsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId - * @param {number} groupId + * + * @param {number} courseId + * @param {number} groupId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3953,8 +4233,8 @@ export const CourseGroupsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3971,8 +4251,8 @@ export const CourseGroupsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -3989,8 +4269,8 @@ export const CourseGroupsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} groupId + * + * @param {number} groupId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4007,8 +4287,8 @@ export const CourseGroupsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} groupId + * + * @param {number} groupId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4025,10 +4305,10 @@ export const CourseGroupsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId - * @param {number} groupId - * @param {string} [userId] + * + * @param {number} courseId + * @param {number} groupId + * @param {string} [userId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4045,10 +4325,10 @@ export const CourseGroupsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId - * @param {number} groupId - * @param {UpdateGroupViewModel} [body] + * + * @param {number} courseId + * @param {number} groupId + * @param {UpdateGroupViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4074,10 +4354,10 @@ export const CourseGroupsApiFp = function(configuration?: Configuration) { export const CourseGroupsApiFactory = function (configuration?: Configuration, fetch?: FetchAPI, basePath?: string) { return { /** - * - * @param {number} courseId - * @param {number} groupId - * @param {string} [userId] + * + * @param {number} courseId + * @param {number} groupId + * @param {string} [userId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4085,9 +4365,9 @@ export const CourseGroupsApiFactory = function (configuration?: Configuration, f return CourseGroupsApiFp(configuration).courseGroupsAddStudentInGroup(courseId, groupId, userId, options)(fetch, basePath); }, /** - * - * @param {number} courseId - * @param {CreateGroupViewModel} [body] + * + * @param {number} courseId + * @param {CreateGroupViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4095,9 +4375,9 @@ export const CourseGroupsApiFactory = function (configuration?: Configuration, f return CourseGroupsApiFp(configuration).courseGroupsCreateCourseGroup(courseId, body, options)(fetch, basePath); }, /** - * - * @param {number} courseId - * @param {number} groupId + * + * @param {number} courseId + * @param {number} groupId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4105,8 +4385,8 @@ export const CourseGroupsApiFactory = function (configuration?: Configuration, f return CourseGroupsApiFp(configuration).courseGroupsDeleteCourseGroup(courseId, groupId, options)(fetch, basePath); }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4114,8 +4394,8 @@ export const CourseGroupsApiFactory = function (configuration?: Configuration, f return CourseGroupsApiFp(configuration).courseGroupsGetAllCourseGroups(courseId, options)(fetch, basePath); }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4123,8 +4403,8 @@ export const CourseGroupsApiFactory = function (configuration?: Configuration, f return CourseGroupsApiFp(configuration).courseGroupsGetCourseGroupsById(courseId, options)(fetch, basePath); }, /** - * - * @param {number} groupId + * + * @param {number} groupId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4132,8 +4412,8 @@ export const CourseGroupsApiFactory = function (configuration?: Configuration, f return CourseGroupsApiFp(configuration).courseGroupsGetGroup(groupId, options)(fetch, basePath); }, /** - * - * @param {number} groupId + * + * @param {number} groupId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4141,10 +4421,10 @@ export const CourseGroupsApiFactory = function (configuration?: Configuration, f return CourseGroupsApiFp(configuration).courseGroupsGetGroupTasks(groupId, options)(fetch, basePath); }, /** - * - * @param {number} courseId - * @param {number} groupId - * @param {string} [userId] + * + * @param {number} courseId + * @param {number} groupId + * @param {string} [userId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4152,10 +4432,10 @@ export const CourseGroupsApiFactory = function (configuration?: Configuration, f return CourseGroupsApiFp(configuration).courseGroupsRemoveStudentFromGroup(courseId, groupId, userId, options)(fetch, basePath); }, /** - * - * @param {number} courseId - * @param {number} groupId - * @param {UpdateGroupViewModel} [body] + * + * @param {number} courseId + * @param {number} groupId + * @param {UpdateGroupViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4173,10 +4453,10 @@ export const CourseGroupsApiFactory = function (configuration?: Configuration, f */ export class CourseGroupsApi extends BaseAPI { /** - * - * @param {number} courseId - * @param {number} groupId - * @param {string} [userId] + * + * @param {number} courseId + * @param {number} groupId + * @param {string} [userId] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CourseGroupsApi @@ -4186,9 +4466,9 @@ export class CourseGroupsApi extends BaseAPI { } /** - * - * @param {number} courseId - * @param {CreateGroupViewModel} [body] + * + * @param {number} courseId + * @param {CreateGroupViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CourseGroupsApi @@ -4198,9 +4478,9 @@ export class CourseGroupsApi extends BaseAPI { } /** - * - * @param {number} courseId - * @param {number} groupId + * + * @param {number} courseId + * @param {number} groupId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CourseGroupsApi @@ -4210,8 +4490,8 @@ export class CourseGroupsApi extends BaseAPI { } /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CourseGroupsApi @@ -4221,8 +4501,8 @@ export class CourseGroupsApi extends BaseAPI { } /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CourseGroupsApi @@ -4232,8 +4512,8 @@ export class CourseGroupsApi extends BaseAPI { } /** - * - * @param {number} groupId + * + * @param {number} groupId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CourseGroupsApi @@ -4243,8 +4523,8 @@ export class CourseGroupsApi extends BaseAPI { } /** - * - * @param {number} groupId + * + * @param {number} groupId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CourseGroupsApi @@ -4254,10 +4534,10 @@ export class CourseGroupsApi extends BaseAPI { } /** - * - * @param {number} courseId - * @param {number} groupId - * @param {string} [userId] + * + * @param {number} courseId + * @param {number} groupId + * @param {string} [userId] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CourseGroupsApi @@ -4267,10 +4547,10 @@ export class CourseGroupsApi extends BaseAPI { } /** - * - * @param {number} courseId - * @param {number} groupId - * @param {UpdateGroupViewModel} [body] + * + * @param {number} courseId + * @param {number} groupId + * @param {UpdateGroupViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CourseGroupsApi @@ -4287,9 +4567,9 @@ export class CourseGroupsApi extends BaseAPI { export const CoursesApiFetchParamCreator = function (configuration?: Configuration) { return { /** - * - * @param {number} courseId - * @param {string} lecturerEmail + * + * @param {number} courseId + * @param {string} lecturerEmail * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4313,8 +4593,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -4329,9 +4609,9 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {number} courseId - * @param {string} studentId + * + * @param {number} courseId + * @param {string} studentId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4355,8 +4635,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -4371,8 +4651,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {CreateCourseViewModel} [body] + * + * @param {CreateCourseViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4386,12 +4666,12 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -4406,8 +4686,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4426,8 +4706,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -4442,10 +4722,10 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {number} courseId - * @param {string} mentorId - * @param {EditMentorWorkspaceDTO} [body] + * + * @param {number} courseId + * @param {string} mentorId + * @param {EditMentorWorkspaceDTO} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4469,12 +4749,12 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -4489,8 +4769,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4509,8 +4789,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -4525,7 +4805,7 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4539,8 +4819,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -4555,8 +4835,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4575,8 +4855,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -4591,7 +4871,7 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4605,8 +4885,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -4621,8 +4901,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4641,8 +4921,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -4657,8 +4937,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {string} [programName] + * + * @param {string} [programName] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4672,8 +4952,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -4692,8 +4972,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4712,8 +4992,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -4728,9 +5008,9 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {number} courseId - * @param {string} mentorId + * + * @param {number} courseId + * @param {string} mentorId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4754,8 +5034,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -4770,7 +5050,7 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4784,8 +5064,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -4800,9 +5080,9 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {number} courseId - * @param {string} studentId + * + * @param {number} courseId + * @param {string} studentId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4826,8 +5106,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -4842,8 +5122,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4862,8 +5142,8 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -4878,9 +5158,9 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {number} courseId - * @param {UpdateCourseViewModel} [body] + * + * @param {number} courseId + * @param {UpdateCourseViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4899,12 +5179,12 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -4919,10 +5199,10 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {number} courseId - * @param {string} studentId - * @param {StudentCharacteristicsDto} [body] + * + * @param {number} courseId + * @param {string} studentId + * @param {StudentCharacteristicsDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4946,12 +5226,12 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -4975,9 +5255,9 @@ export const CoursesApiFetchParamCreator = function (configuration?: Configurati export const CoursesApiFp = function(configuration?: Configuration) { return { /** - * - * @param {number} courseId - * @param {string} lecturerEmail + * + * @param {number} courseId + * @param {string} lecturerEmail * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -4994,9 +5274,9 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId - * @param {string} studentId + * + * @param {number} courseId + * @param {string} studentId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5013,8 +5293,8 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {CreateCourseViewModel} [body] + * + * @param {CreateCourseViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5031,8 +5311,8 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5049,10 +5329,10 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId - * @param {string} mentorId - * @param {EditMentorWorkspaceDTO} [body] + * + * @param {number} courseId + * @param {string} mentorId + * @param {EditMentorWorkspaceDTO} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5069,12 +5349,12 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ - coursesGetAllCourseData(courseId: number, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { + coursesGetAllCourseData(courseId: number, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { const localVarFetchArgs = CoursesApiFetchParamCreator(configuration).coursesGetAllCourseData(courseId, options); return (fetch: FetchAPI = isomorphicFetch, basePath: string = BASE_PATH) => { return fetch(basePath + localVarFetchArgs.url, localVarFetchArgs.options).then((response) => { @@ -5087,7 +5367,7 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5104,8 +5384,8 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5122,7 +5402,7 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5139,8 +5419,8 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5157,8 +5437,8 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {string} [programName] + * + * @param {string} [programName] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5175,8 +5455,8 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5193,9 +5473,9 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId - * @param {string} mentorId + * + * @param {number} courseId + * @param {string} mentorId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5212,7 +5492,7 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5229,9 +5509,9 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId - * @param {string} studentId + * + * @param {number} courseId + * @param {string} studentId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5248,8 +5528,8 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5266,9 +5546,9 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId - * @param {UpdateCourseViewModel} [body] + * + * @param {number} courseId + * @param {UpdateCourseViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5285,10 +5565,10 @@ export const CoursesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId - * @param {string} studentId - * @param {StudentCharacteristicsDto} [body] + * + * @param {number} courseId + * @param {string} studentId + * @param {StudentCharacteristicsDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5314,9 +5594,9 @@ export const CoursesApiFp = function(configuration?: Configuration) { export const CoursesApiFactory = function (configuration?: Configuration, fetch?: FetchAPI, basePath?: string) { return { /** - * - * @param {number} courseId - * @param {string} lecturerEmail + * + * @param {number} courseId + * @param {string} lecturerEmail * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5324,9 +5604,9 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesAcceptLecturer(courseId, lecturerEmail, options)(fetch, basePath); }, /** - * - * @param {number} courseId - * @param {string} studentId + * + * @param {number} courseId + * @param {string} studentId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5334,8 +5614,8 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesAcceptStudent(courseId, studentId, options)(fetch, basePath); }, /** - * - * @param {CreateCourseViewModel} [body] + * + * @param {CreateCourseViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5343,8 +5623,8 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesCreateCourse(body, options)(fetch, basePath); }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5352,10 +5632,10 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesDeleteCourse(courseId, options)(fetch, basePath); }, /** - * - * @param {number} courseId - * @param {string} mentorId - * @param {EditMentorWorkspaceDTO} [body] + * + * @param {number} courseId + * @param {string} mentorId + * @param {EditMentorWorkspaceDTO} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5363,8 +5643,8 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesEditMentorWorkspace(courseId, mentorId, body, options)(fetch, basePath); }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5372,7 +5652,7 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesGetAllCourseData(courseId, options)(fetch, basePath); }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5380,8 +5660,8 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesGetAllCourses(options)(fetch, basePath); }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5389,7 +5669,7 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesGetAllTagsForCourse(courseId, options)(fetch, basePath); }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5397,8 +5677,8 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesGetAllUserCourses(options)(fetch, basePath); }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5406,8 +5686,8 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesGetCourseData(courseId, options)(fetch, basePath); }, /** - * - * @param {string} [programName] + * + * @param {string} [programName] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5415,8 +5695,8 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesGetGroups(programName, options)(fetch, basePath); }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5424,9 +5704,9 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesGetLecturersAvailableForCourse(courseId, options)(fetch, basePath); }, /** - * - * @param {number} courseId - * @param {string} mentorId + * + * @param {number} courseId + * @param {string} mentorId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5434,7 +5714,7 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesGetMentorWorkspace(courseId, mentorId, options)(fetch, basePath); }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5442,9 +5722,9 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesGetProgramNames(options)(fetch, basePath); }, /** - * - * @param {number} courseId - * @param {string} studentId + * + * @param {number} courseId + * @param {string} studentId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5452,8 +5732,8 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesRejectStudent(courseId, studentId, options)(fetch, basePath); }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5461,9 +5741,9 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesSignInCourse(courseId, options)(fetch, basePath); }, /** - * - * @param {number} courseId - * @param {UpdateCourseViewModel} [body] + * + * @param {number} courseId + * @param {UpdateCourseViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5471,10 +5751,10 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? return CoursesApiFp(configuration).coursesUpdateCourse(courseId, body, options)(fetch, basePath); }, /** - * - * @param {number} courseId - * @param {string} studentId - * @param {StudentCharacteristicsDto} [body] + * + * @param {number} courseId + * @param {string} studentId + * @param {StudentCharacteristicsDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5492,9 +5772,9 @@ export const CoursesApiFactory = function (configuration?: Configuration, fetch? */ export class CoursesApi extends BaseAPI { /** - * - * @param {number} courseId - * @param {string} lecturerEmail + * + * @param {number} courseId + * @param {string} lecturerEmail * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5504,9 +5784,9 @@ export class CoursesApi extends BaseAPI { } /** - * - * @param {number} courseId - * @param {string} studentId + * + * @param {number} courseId + * @param {string} studentId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5516,8 +5796,8 @@ export class CoursesApi extends BaseAPI { } /** - * - * @param {CreateCourseViewModel} [body] + * + * @param {CreateCourseViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5527,8 +5807,8 @@ export class CoursesApi extends BaseAPI { } /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5538,10 +5818,10 @@ export class CoursesApi extends BaseAPI { } /** - * - * @param {number} courseId - * @param {string} mentorId - * @param {EditMentorWorkspaceDTO} [body] + * + * @param {number} courseId + * @param {string} mentorId + * @param {EditMentorWorkspaceDTO} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5551,8 +5831,8 @@ export class CoursesApi extends BaseAPI { } /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5562,7 +5842,7 @@ export class CoursesApi extends BaseAPI { } /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5572,8 +5852,8 @@ export class CoursesApi extends BaseAPI { } /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5583,7 +5863,7 @@ export class CoursesApi extends BaseAPI { } /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5593,8 +5873,8 @@ export class CoursesApi extends BaseAPI { } /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5604,8 +5884,8 @@ export class CoursesApi extends BaseAPI { } /** - * - * @param {string} [programName] + * + * @param {string} [programName] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5615,8 +5895,8 @@ export class CoursesApi extends BaseAPI { } /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5626,9 +5906,9 @@ export class CoursesApi extends BaseAPI { } /** - * - * @param {number} courseId - * @param {string} mentorId + * + * @param {number} courseId + * @param {string} mentorId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5638,7 +5918,7 @@ export class CoursesApi extends BaseAPI { } /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5648,9 +5928,9 @@ export class CoursesApi extends BaseAPI { } /** - * - * @param {number} courseId - * @param {string} studentId + * + * @param {number} courseId + * @param {string} studentId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5660,8 +5940,8 @@ export class CoursesApi extends BaseAPI { } /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5671,9 +5951,9 @@ export class CoursesApi extends BaseAPI { } /** - * - * @param {number} courseId - * @param {UpdateCourseViewModel} [body] + * + * @param {number} courseId + * @param {UpdateCourseViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5683,10 +5963,10 @@ export class CoursesApi extends BaseAPI { } /** - * - * @param {number} courseId - * @param {string} studentId - * @param {StudentCharacteristicsDto} [body] + * + * @param {number} courseId + * @param {string} studentId + * @param {StudentCharacteristicsDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof CoursesApi @@ -5703,7 +5983,7 @@ export class CoursesApi extends BaseAPI { export const ExpertsApiFetchParamCreator = function (configuration?: Configuration) { return { /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5717,8 +5997,8 @@ export const ExpertsApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -5733,7 +6013,7 @@ export const ExpertsApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5747,8 +6027,8 @@ export const ExpertsApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -5763,8 +6043,8 @@ export const ExpertsApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {string} [expertEmail] + * + * @param {string} [expertEmail] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5778,8 +6058,8 @@ export const ExpertsApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -5798,8 +6078,8 @@ export const ExpertsApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {InviteExpertViewModel} [body] + * + * @param {InviteExpertViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5813,12 +6093,12 @@ export const ExpertsApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -5833,8 +6113,8 @@ export const ExpertsApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {TokenCredentials} [body] + * + * @param {TokenCredentials} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5848,12 +6128,12 @@ export const ExpertsApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -5868,8 +6148,8 @@ export const ExpertsApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {RegisterExpertViewModel} [body] + * + * @param {RegisterExpertViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5883,12 +6163,12 @@ export const ExpertsApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -5903,7 +6183,7 @@ export const ExpertsApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5917,8 +6197,8 @@ export const ExpertsApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -5933,8 +6213,8 @@ export const ExpertsApiFetchParamCreator = function (configuration?: Configurati }; }, /** - * - * @param {UpdateExpertTagsDTO} [body] + * + * @param {UpdateExpertTagsDTO} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5948,12 +6228,12 @@ export const ExpertsApiFetchParamCreator = function (configuration?: Configurati // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -5977,7 +6257,7 @@ export const ExpertsApiFetchParamCreator = function (configuration?: Configurati export const ExpertsApiFp = function(configuration?: Configuration) { return { /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -5994,7 +6274,7 @@ export const ExpertsApiFp = function(configuration?: Configuration) { }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6011,8 +6291,8 @@ export const ExpertsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {string} [expertEmail] + * + * @param {string} [expertEmail] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6029,8 +6309,8 @@ export const ExpertsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {InviteExpertViewModel} [body] + * + * @param {InviteExpertViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6047,8 +6327,8 @@ export const ExpertsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {TokenCredentials} [body] + * + * @param {TokenCredentials} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6065,8 +6345,8 @@ export const ExpertsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {RegisterExpertViewModel} [body] + * + * @param {RegisterExpertViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6083,7 +6363,7 @@ export const ExpertsApiFp = function(configuration?: Configuration) { }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6100,8 +6380,8 @@ export const ExpertsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {UpdateExpertTagsDTO} [body] + * + * @param {UpdateExpertTagsDTO} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6127,7 +6407,7 @@ export const ExpertsApiFp = function(configuration?: Configuration) { export const ExpertsApiFactory = function (configuration?: Configuration, fetch?: FetchAPI, basePath?: string) { return { /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6135,7 +6415,7 @@ export const ExpertsApiFactory = function (configuration?: Configuration, fetch? return ExpertsApiFp(configuration).expertsGetAll(options)(fetch, basePath); }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6143,8 +6423,8 @@ export const ExpertsApiFactory = function (configuration?: Configuration, fetch? return ExpertsApiFp(configuration).expertsGetIsProfileEdited(options)(fetch, basePath); }, /** - * - * @param {string} [expertEmail] + * + * @param {string} [expertEmail] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6152,8 +6432,8 @@ export const ExpertsApiFactory = function (configuration?: Configuration, fetch? return ExpertsApiFp(configuration).expertsGetToken(expertEmail, options)(fetch, basePath); }, /** - * - * @param {InviteExpertViewModel} [body] + * + * @param {InviteExpertViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6161,8 +6441,8 @@ export const ExpertsApiFactory = function (configuration?: Configuration, fetch? return ExpertsApiFp(configuration).expertsInvite(body, options)(fetch, basePath); }, /** - * - * @param {TokenCredentials} [body] + * + * @param {TokenCredentials} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6170,8 +6450,8 @@ export const ExpertsApiFactory = function (configuration?: Configuration, fetch? return ExpertsApiFp(configuration).expertsLogin(body, options)(fetch, basePath); }, /** - * - * @param {RegisterExpertViewModel} [body] + * + * @param {RegisterExpertViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6179,7 +6459,7 @@ export const ExpertsApiFactory = function (configuration?: Configuration, fetch? return ExpertsApiFp(configuration).expertsRegister(body, options)(fetch, basePath); }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6187,8 +6467,8 @@ export const ExpertsApiFactory = function (configuration?: Configuration, fetch? return ExpertsApiFp(configuration).expertsSetProfileIsEdited(options)(fetch, basePath); }, /** - * - * @param {UpdateExpertTagsDTO} [body] + * + * @param {UpdateExpertTagsDTO} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6206,7 +6486,7 @@ export const ExpertsApiFactory = function (configuration?: Configuration, fetch? */ export class ExpertsApi extends BaseAPI { /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof ExpertsApi @@ -6216,7 +6496,7 @@ export class ExpertsApi extends BaseAPI { } /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof ExpertsApi @@ -6226,8 +6506,8 @@ export class ExpertsApi extends BaseAPI { } /** - * - * @param {string} [expertEmail] + * + * @param {string} [expertEmail] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof ExpertsApi @@ -6237,8 +6517,8 @@ export class ExpertsApi extends BaseAPI { } /** - * - * @param {InviteExpertViewModel} [body] + * + * @param {InviteExpertViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof ExpertsApi @@ -6248,8 +6528,8 @@ export class ExpertsApi extends BaseAPI { } /** - * - * @param {TokenCredentials} [body] + * + * @param {TokenCredentials} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof ExpertsApi @@ -6259,8 +6539,8 @@ export class ExpertsApi extends BaseAPI { } /** - * - * @param {RegisterExpertViewModel} [body] + * + * @param {RegisterExpertViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof ExpertsApi @@ -6270,7 +6550,7 @@ export class ExpertsApi extends BaseAPI { } /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof ExpertsApi @@ -6280,8 +6560,8 @@ export class ExpertsApi extends BaseAPI { } /** - * - * @param {UpdateExpertTagsDTO} [body] + * + * @param {UpdateExpertTagsDTO} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof ExpertsApi @@ -6298,33 +6578,28 @@ export class ExpertsApi extends BaseAPI { export const FilesApiFetchParamCreator = function (configuration?: Configuration) { return { /** - * - * @param {number} [courseId] - * @param {string} [key] + * + * @param {number} [fileId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - filesDeleteFile(courseId?: number, key?: string, options: any = {}): FetchArgs { - const localVarPath = `/api/Files`; + filesGetDownloadLink(fileId?: number, options: any = {}): FetchArgs { + const localVarPath = `/api/Files/downloadLink`; const localVarUrlObj = url.parse(localVarPath, true); - const localVarRequestOptions = Object.assign({ method: 'DELETE' }, options); + const localVarRequestOptions = Object.assign({ method: 'GET' }, options); const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - if (courseId !== undefined) { - localVarQueryParameter['courseId'] = courseId; - } - - if (key !== undefined) { - localVarQueryParameter['key'] = key; + if (fileId !== undefined) { + localVarQueryParameter['fileId'] = fileId; } localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); @@ -6338,13 +6613,20 @@ export const FilesApiFetchParamCreator = function (configuration?: Configuration }; }, /** - * - * @param {string} [key] + * + * @param {number} courseId + * @param {boolean} [uploadedOnly] + * @param {string} [courseUnitType] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - filesGetDownloadLink(key?: string, options: any = {}): FetchArgs { - const localVarPath = `/api/Files/downloadLink`; + filesGetFilesInfo(courseId: number, uploadedOnly?: boolean, courseUnitType?: string, options: any = {}): FetchArgs { + // verify required parameter 'courseId' is not null or undefined + if (courseId === null || courseId === undefined) { + throw new RequiredError('courseId','Required parameter courseId was null or undefined when calling filesGetFilesInfo.'); + } + const localVarPath = `/api/Files/info/course/{courseId}` + .replace(`{${"courseId"}}`, encodeURIComponent(String(courseId))); const localVarUrlObj = url.parse(localVarPath, true); const localVarRequestOptions = Object.assign({ method: 'GET' }, options); const localVarHeaderParameter = {} as any; @@ -6353,13 +6635,17 @@ export const FilesApiFetchParamCreator = function (configuration?: Configuration // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - if (key !== undefined) { - localVarQueryParameter['key'] = key; + if (uploadedOnly !== undefined) { + localVarQueryParameter['uploadedOnly'] = uploadedOnly; + } + + if (courseUnitType !== undefined) { + localVarQueryParameter['courseUnitType'] = courseUnitType; } localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); @@ -6373,40 +6659,34 @@ export const FilesApiFetchParamCreator = function (configuration?: Configuration }; }, /** - * - * @param {number} courseId - * @param {number} [homeworkId] + * + * @param {ScopeDTO} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - filesGetFilesInfo(courseId: number, homeworkId?: number, options: any = {}): FetchArgs { - // verify required parameter 'courseId' is not null or undefined - if (courseId === null || courseId === undefined) { - throw new RequiredError('courseId','Required parameter courseId was null or undefined when calling filesGetFilesInfo.'); - } - const localVarPath = `/api/Files/filesInfo/{courseId}` - .replace(`{${"courseId"}}`, encodeURIComponent(String(courseId))); + filesGetStatuses(body?: ScopeDTO, options: any = {}): FetchArgs { + const localVarPath = `/api/Files/statuses`; const localVarUrlObj = url.parse(localVarPath, true); - const localVarRequestOptions = Object.assign({ method: 'GET' }, options); + const localVarRequestOptions = Object.assign({ method: 'POST' }, options); const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - if (homeworkId !== undefined) { - localVarQueryParameter['homeworkId'] = homeworkId; - } + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 localVarUrlObj.search = null; localVarRequestOptions.headers = Object.assign({}, localVarHeaderParameter, options.headers); + const needsSerialization = ("ScopeDTO" !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; + localVarRequestOptions.body = needsSerialization ? JSON.stringify(body || {}) : (body || ""); return { url: url.format(localVarUrlObj), @@ -6414,15 +6694,17 @@ export const FilesApiFetchParamCreator = function (configuration?: Configuration }; }, /** - * - * @param {number} [courseId] - * @param {number} [homeworkId] - * @param {Blob} [file] + * + * @param {number} [filesScopeCourseId] + * @param {string} [filesScopeCourseUnitType] + * @param {number} [filesScopeCourseUnitId] + * @param {Array} [deletingFileIds] + * @param {Array} [newFiles] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - filesUpload(courseId?: number, homeworkId?: number, file?: Blob, options: any = {}): FetchArgs { - const localVarPath = `/api/Files/upload`; + filesProcess(filesScopeCourseId?: number, filesScopeCourseUnitType?: string, filesScopeCourseUnitId?: number, deletingFileIds?: Array, newFiles?: Array, options: any = {}): FetchArgs { + const localVarPath = `/api/Files/process`; const localVarUrlObj = url.parse(localVarPath, true); const localVarRequestOptions = Object.assign({ method: 'POST' }, options); const localVarHeaderParameter = {} as any; @@ -6432,21 +6714,33 @@ export const FilesApiFetchParamCreator = function (configuration?: Configuration // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - if (courseId !== undefined) { - localVarFormParams.set('CourseId', courseId as any); + if (filesScopeCourseId !== undefined) { + localVarFormParams.set('FilesScope.CourseId', filesScopeCourseId as any); } - if (homeworkId !== undefined) { - localVarFormParams.set('HomeworkId', homeworkId as any); + if (filesScopeCourseUnitType !== undefined) { + localVarFormParams.set('FilesScope.CourseUnitType', filesScopeCourseUnitType as any); } - if (file !== undefined) { - localVarFormParams.set('File', file as any); + if (filesScopeCourseUnitId !== undefined) { + localVarFormParams.set('FilesScope.CourseUnitId', filesScopeCourseUnitId as any); + } + + if (deletingFileIds) { + deletingFileIds.forEach((element) => { + localVarFormParams.append('DeletingFileIds', element as any); + }) + } + + if (newFiles) { + newFiles.forEach((element) => { + localVarFormParams.append('NewFiles', element as any); + }) } localVarHeaderParameter['Content-Type'] = 'application/x-www-form-urlencoded'; @@ -6472,18 +6766,17 @@ export const FilesApiFetchParamCreator = function (configuration?: Configuration export const FilesApiFp = function(configuration?: Configuration) { return { /** - * - * @param {number} [courseId] - * @param {string} [key] + * + * @param {number} [fileId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - filesDeleteFile(courseId?: number, key?: string, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { - const localVarFetchArgs = FilesApiFetchParamCreator(configuration).filesDeleteFile(courseId, key, options); + filesGetDownloadLink(fileId?: number, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { + const localVarFetchArgs = FilesApiFetchParamCreator(configuration).filesGetDownloadLink(fileId, options); return (fetch: FetchAPI = isomorphicFetch, basePath: string = BASE_PATH) => { return fetch(basePath + localVarFetchArgs.url, localVarFetchArgs.options).then((response) => { if (response.status >= 200 && response.status < 300) { - return response; + return response.json(); } else { throw response; } @@ -6491,13 +6784,15 @@ export const FilesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {string} [key] + * + * @param {number} courseId + * @param {boolean} [uploadedOnly] + * @param {string} [courseUnitType] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - filesGetDownloadLink(key?: string, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { - const localVarFetchArgs = FilesApiFetchParamCreator(configuration).filesGetDownloadLink(key, options); + filesGetFilesInfo(courseId: number, uploadedOnly?: boolean, courseUnitType?: string, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise> { + const localVarFetchArgs = FilesApiFetchParamCreator(configuration).filesGetFilesInfo(courseId, uploadedOnly, courseUnitType, options); return (fetch: FetchAPI = isomorphicFetch, basePath: string = BASE_PATH) => { return fetch(basePath + localVarFetchArgs.url, localVarFetchArgs.options).then((response) => { if (response.status >= 200 && response.status < 300) { @@ -6509,14 +6804,13 @@ export const FilesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId - * @param {number} [homeworkId] + * + * @param {ScopeDTO} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - filesGetFilesInfo(courseId: number, homeworkId?: number, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise> { - const localVarFetchArgs = FilesApiFetchParamCreator(configuration).filesGetFilesInfo(courseId, homeworkId, options); + filesGetStatuses(body?: ScopeDTO, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise> { + const localVarFetchArgs = FilesApiFetchParamCreator(configuration).filesGetStatuses(body, options); return (fetch: FetchAPI = isomorphicFetch, basePath: string = BASE_PATH) => { return fetch(basePath + localVarFetchArgs.url, localVarFetchArgs.options).then((response) => { if (response.status >= 200 && response.status < 300) { @@ -6528,15 +6822,17 @@ export const FilesApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} [courseId] - * @param {number} [homeworkId] - * @param {Blob} [file] + * + * @param {number} [filesScopeCourseId] + * @param {string} [filesScopeCourseUnitType] + * @param {number} [filesScopeCourseUnitId] + * @param {Array} [deletingFileIds] + * @param {Array} [newFiles] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - filesUpload(courseId?: number, homeworkId?: number, file?: Blob, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { - const localVarFetchArgs = FilesApiFetchParamCreator(configuration).filesUpload(courseId, homeworkId, file, options); + filesProcess(filesScopeCourseId?: number, filesScopeCourseUnitType?: string, filesScopeCourseUnitId?: number, deletingFileIds?: Array, newFiles?: Array, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { + const localVarFetchArgs = FilesApiFetchParamCreator(configuration).filesProcess(filesScopeCourseId, filesScopeCourseUnitType, filesScopeCourseUnitId, deletingFileIds, newFiles, options); return (fetch: FetchAPI = isomorphicFetch, basePath: string = BASE_PATH) => { return fetch(basePath + localVarFetchArgs.url, localVarFetchArgs.options).then((response) => { if (response.status >= 200 && response.status < 300) { @@ -6557,44 +6853,46 @@ export const FilesApiFp = function(configuration?: Configuration) { export const FilesApiFactory = function (configuration?: Configuration, fetch?: FetchAPI, basePath?: string) { return { /** - * - * @param {number} [courseId] - * @param {string} [key] + * + * @param {number} [fileId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - filesDeleteFile(courseId?: number, key?: string, options?: any) { - return FilesApiFp(configuration).filesDeleteFile(courseId, key, options)(fetch, basePath); + filesGetDownloadLink(fileId?: number, options?: any) { + return FilesApiFp(configuration).filesGetDownloadLink(fileId, options)(fetch, basePath); }, /** - * - * @param {string} [key] + * + * @param {number} courseId + * @param {boolean} [uploadedOnly] + * @param {string} [courseUnitType] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - filesGetDownloadLink(key?: string, options?: any) { - return FilesApiFp(configuration).filesGetDownloadLink(key, options)(fetch, basePath); + filesGetFilesInfo(courseId: number, uploadedOnly?: boolean, courseUnitType?: string, options?: any) { + return FilesApiFp(configuration).filesGetFilesInfo(courseId, uploadedOnly, courseUnitType, options)(fetch, basePath); }, /** - * - * @param {number} courseId - * @param {number} [homeworkId] + * + * @param {ScopeDTO} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - filesGetFilesInfo(courseId: number, homeworkId?: number, options?: any) { - return FilesApiFp(configuration).filesGetFilesInfo(courseId, homeworkId, options)(fetch, basePath); + filesGetStatuses(body?: ScopeDTO, options?: any) { + return FilesApiFp(configuration).filesGetStatuses(body, options)(fetch, basePath); }, /** - * - * @param {number} [courseId] - * @param {number} [homeworkId] - * @param {Blob} [file] + * + * @param {number} [filesScopeCourseId] + * @param {string} [filesScopeCourseUnitType] + * @param {number} [filesScopeCourseUnitId] + * @param {Array} [deletingFileIds] + * @param {Array} [newFiles] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - filesUpload(courseId?: number, homeworkId?: number, file?: Blob, options?: any) { - return FilesApiFp(configuration).filesUpload(courseId, homeworkId, file, options)(fetch, basePath); + filesProcess(filesScopeCourseId?: number, filesScopeCourseUnitType?: string, filesScopeCourseUnitId?: number, deletingFileIds?: Array, newFiles?: Array, options?: any) { + return FilesApiFp(configuration).filesProcess(filesScopeCourseId, filesScopeCourseUnitType, filesScopeCourseUnitId, deletingFileIds, newFiles, options)(fetch, basePath); }, }; }; @@ -6607,51 +6905,53 @@ export const FilesApiFactory = function (configuration?: Configuration, fetch?: */ export class FilesApi extends BaseAPI { /** - * - * @param {number} [courseId] - * @param {string} [key] + * + * @param {number} [fileId] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof FilesApi */ - public filesDeleteFile(courseId?: number, key?: string, options?: any) { - return FilesApiFp(this.configuration).filesDeleteFile(courseId, key, options)(this.fetch, this.basePath); + public filesGetDownloadLink(fileId?: number, options?: any) { + return FilesApiFp(this.configuration).filesGetDownloadLink(fileId, options)(this.fetch, this.basePath); } /** - * - * @param {string} [key] + * + * @param {number} courseId + * @param {boolean} [uploadedOnly] + * @param {string} [courseUnitType] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof FilesApi */ - public filesGetDownloadLink(key?: string, options?: any) { - return FilesApiFp(this.configuration).filesGetDownloadLink(key, options)(this.fetch, this.basePath); + public filesGetFilesInfo(courseId: number, uploadedOnly?: boolean, courseUnitType?: string, options?: any) { + return FilesApiFp(this.configuration).filesGetFilesInfo(courseId, uploadedOnly, courseUnitType, options)(this.fetch, this.basePath); } /** - * - * @param {number} courseId - * @param {number} [homeworkId] + * + * @param {ScopeDTO} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof FilesApi */ - public filesGetFilesInfo(courseId: number, homeworkId?: number, options?: any) { - return FilesApiFp(this.configuration).filesGetFilesInfo(courseId, homeworkId, options)(this.fetch, this.basePath); + public filesGetStatuses(body?: ScopeDTO, options?: any) { + return FilesApiFp(this.configuration).filesGetStatuses(body, options)(this.fetch, this.basePath); } /** - * - * @param {number} [courseId] - * @param {number} [homeworkId] - * @param {Blob} [file] + * + * @param {number} [filesScopeCourseId] + * @param {string} [filesScopeCourseUnitType] + * @param {number} [filesScopeCourseUnitId] + * @param {Array} [deletingFileIds] + * @param {Array} [newFiles] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof FilesApi */ - public filesUpload(courseId?: number, homeworkId?: number, file?: Blob, options?: any) { - return FilesApiFp(this.configuration).filesUpload(courseId, homeworkId, file, options)(this.fetch, this.basePath); + public filesProcess(filesScopeCourseId?: number, filesScopeCourseUnitType?: string, filesScopeCourseUnitId?: number, deletingFileIds?: Array, newFiles?: Array, options?: any) { + return FilesApiFp(this.configuration).filesProcess(filesScopeCourseId, filesScopeCourseUnitType, filesScopeCourseUnitId, deletingFileIds, newFiles, options)(this.fetch, this.basePath); } } @@ -6662,9 +6962,9 @@ export class FilesApi extends BaseAPI { export const HomeworksApiFetchParamCreator = function (configuration?: Configuration) { return { /** - * - * @param {number} courseId - * @param {CreateHomeworkViewModel} [body] + * + * @param {number} courseId + * @param {CreateHomeworkViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6683,12 +6983,12 @@ export const HomeworksApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -6703,8 +7003,8 @@ export const HomeworksApiFetchParamCreator = function (configuration?: Configura }; }, /** - * - * @param {number} homeworkId + * + * @param {number} homeworkId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6723,8 +7023,8 @@ export const HomeworksApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -6739,8 +7039,8 @@ export const HomeworksApiFetchParamCreator = function (configuration?: Configura }; }, /** - * - * @param {number} homeworkId + * + * @param {number} homeworkId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6759,8 +7059,8 @@ export const HomeworksApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -6775,8 +7075,8 @@ export const HomeworksApiFetchParamCreator = function (configuration?: Configura }; }, /** - * - * @param {number} homeworkId + * + * @param {number} homeworkId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6795,8 +7095,8 @@ export const HomeworksApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -6811,9 +7111,9 @@ export const HomeworksApiFetchParamCreator = function (configuration?: Configura }; }, /** - * - * @param {number} homeworkId - * @param {CreateHomeworkViewModel} [body] + * + * @param {number} homeworkId + * @param {CreateHomeworkViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6832,12 +7132,12 @@ export const HomeworksApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -6861,13 +7161,13 @@ export const HomeworksApiFetchParamCreator = function (configuration?: Configura export const HomeworksApiFp = function(configuration?: Configuration) { return { /** - * - * @param {number} courseId - * @param {CreateHomeworkViewModel} [body] + * + * @param {number} courseId + * @param {CreateHomeworkViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - homeworksAddHomework(courseId: number, body?: CreateHomeworkViewModel, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { + homeworksAddHomework(courseId: number, body?: CreateHomeworkViewModel, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { const localVarFetchArgs = HomeworksApiFetchParamCreator(configuration).homeworksAddHomework(courseId, body, options); return (fetch: FetchAPI = isomorphicFetch, basePath: string = BASE_PATH) => { return fetch(basePath + localVarFetchArgs.url, localVarFetchArgs.options).then((response) => { @@ -6880,8 +7180,8 @@ export const HomeworksApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} homeworkId + * + * @param {number} homeworkId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6898,8 +7198,8 @@ export const HomeworksApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} homeworkId + * + * @param {number} homeworkId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6916,8 +7216,8 @@ export const HomeworksApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} homeworkId + * + * @param {number} homeworkId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6934,9 +7234,9 @@ export const HomeworksApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} homeworkId - * @param {CreateHomeworkViewModel} [body] + * + * @param {number} homeworkId + * @param {CreateHomeworkViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6962,9 +7262,9 @@ export const HomeworksApiFp = function(configuration?: Configuration) { export const HomeworksApiFactory = function (configuration?: Configuration, fetch?: FetchAPI, basePath?: string) { return { /** - * - * @param {number} courseId - * @param {CreateHomeworkViewModel} [body] + * + * @param {number} courseId + * @param {CreateHomeworkViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6972,8 +7272,8 @@ export const HomeworksApiFactory = function (configuration?: Configuration, fetc return HomeworksApiFp(configuration).homeworksAddHomework(courseId, body, options)(fetch, basePath); }, /** - * - * @param {number} homeworkId + * + * @param {number} homeworkId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6981,8 +7281,8 @@ export const HomeworksApiFactory = function (configuration?: Configuration, fetc return HomeworksApiFp(configuration).homeworksDeleteHomework(homeworkId, options)(fetch, basePath); }, /** - * - * @param {number} homeworkId + * + * @param {number} homeworkId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6990,8 +7290,8 @@ export const HomeworksApiFactory = function (configuration?: Configuration, fetc return HomeworksApiFp(configuration).homeworksGetForEditingHomework(homeworkId, options)(fetch, basePath); }, /** - * - * @param {number} homeworkId + * + * @param {number} homeworkId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -6999,9 +7299,9 @@ export const HomeworksApiFactory = function (configuration?: Configuration, fetc return HomeworksApiFp(configuration).homeworksGetHomework(homeworkId, options)(fetch, basePath); }, /** - * - * @param {number} homeworkId - * @param {CreateHomeworkViewModel} [body] + * + * @param {number} homeworkId + * @param {CreateHomeworkViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7019,9 +7319,9 @@ export const HomeworksApiFactory = function (configuration?: Configuration, fetc */ export class HomeworksApi extends BaseAPI { /** - * - * @param {number} courseId - * @param {CreateHomeworkViewModel} [body] + * + * @param {number} courseId + * @param {CreateHomeworkViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof HomeworksApi @@ -7031,8 +7331,8 @@ export class HomeworksApi extends BaseAPI { } /** - * - * @param {number} homeworkId + * + * @param {number} homeworkId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof HomeworksApi @@ -7042,8 +7342,8 @@ export class HomeworksApi extends BaseAPI { } /** - * - * @param {number} homeworkId + * + * @param {number} homeworkId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof HomeworksApi @@ -7053,8 +7353,8 @@ export class HomeworksApi extends BaseAPI { } /** - * - * @param {number} homeworkId + * + * @param {number} homeworkId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof HomeworksApi @@ -7064,9 +7364,9 @@ export class HomeworksApi extends BaseAPI { } /** - * - * @param {number} homeworkId - * @param {CreateHomeworkViewModel} [body] + * + * @param {number} homeworkId + * @param {CreateHomeworkViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof HomeworksApi @@ -7083,8 +7383,8 @@ export class HomeworksApi extends BaseAPI { export const NotificationsApiFetchParamCreator = function (configuration?: Configuration) { return { /** - * - * @param {NotificationsSettingDto} [body] + * + * @param {NotificationsSettingDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7098,12 +7398,12 @@ export const NotificationsApiFetchParamCreator = function (configuration?: Confi // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -7118,7 +7418,7 @@ export const NotificationsApiFetchParamCreator = function (configuration?: Confi }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7132,8 +7432,8 @@ export const NotificationsApiFetchParamCreator = function (configuration?: Confi // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -7148,7 +7448,7 @@ export const NotificationsApiFetchParamCreator = function (configuration?: Confi }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7162,8 +7462,8 @@ export const NotificationsApiFetchParamCreator = function (configuration?: Confi // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -7178,7 +7478,7 @@ export const NotificationsApiFetchParamCreator = function (configuration?: Confi }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7192,8 +7492,8 @@ export const NotificationsApiFetchParamCreator = function (configuration?: Confi // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -7208,8 +7508,8 @@ export const NotificationsApiFetchParamCreator = function (configuration?: Confi }; }, /** - * - * @param {Array} [body] + * + * @param {Array} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7223,12 +7523,12 @@ export const NotificationsApiFetchParamCreator = function (configuration?: Confi // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -7252,8 +7552,8 @@ export const NotificationsApiFetchParamCreator = function (configuration?: Confi export const NotificationsApiFp = function(configuration?: Configuration) { return { /** - * - * @param {NotificationsSettingDto} [body] + * + * @param {NotificationsSettingDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7270,7 +7570,7 @@ export const NotificationsApiFp = function(configuration?: Configuration) { }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7287,7 +7587,7 @@ export const NotificationsApiFp = function(configuration?: Configuration) { }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7304,7 +7604,7 @@ export const NotificationsApiFp = function(configuration?: Configuration) { }; }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7321,8 +7621,8 @@ export const NotificationsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {Array} [body] + * + * @param {Array} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7348,8 +7648,8 @@ export const NotificationsApiFp = function(configuration?: Configuration) { export const NotificationsApiFactory = function (configuration?: Configuration, fetch?: FetchAPI, basePath?: string) { return { /** - * - * @param {NotificationsSettingDto} [body] + * + * @param {NotificationsSettingDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7357,7 +7657,7 @@ export const NotificationsApiFactory = function (configuration?: Configuration, return NotificationsApiFp(configuration).notificationsChangeSetting(body, options)(fetch, basePath); }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7365,7 +7665,7 @@ export const NotificationsApiFactory = function (configuration?: Configuration, return NotificationsApiFp(configuration).notificationsGet(options)(fetch, basePath); }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7373,7 +7673,7 @@ export const NotificationsApiFactory = function (configuration?: Configuration, return NotificationsApiFp(configuration).notificationsGetNewNotificationsCount(options)(fetch, basePath); }, /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7381,8 +7681,8 @@ export const NotificationsApiFactory = function (configuration?: Configuration, return NotificationsApiFp(configuration).notificationsGetSettings(options)(fetch, basePath); }, /** - * - * @param {Array} [body] + * + * @param {Array} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7400,8 +7700,8 @@ export const NotificationsApiFactory = function (configuration?: Configuration, */ export class NotificationsApi extends BaseAPI { /** - * - * @param {NotificationsSettingDto} [body] + * + * @param {NotificationsSettingDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof NotificationsApi @@ -7411,7 +7711,7 @@ export class NotificationsApi extends BaseAPI { } /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof NotificationsApi @@ -7421,7 +7721,7 @@ export class NotificationsApi extends BaseAPI { } /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof NotificationsApi @@ -7431,7 +7731,7 @@ export class NotificationsApi extends BaseAPI { } /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof NotificationsApi @@ -7441,8 +7741,8 @@ export class NotificationsApi extends BaseAPI { } /** - * - * @param {Array} [body] + * + * @param {Array} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof NotificationsApi @@ -7459,8 +7759,8 @@ export class NotificationsApi extends BaseAPI { export const SolutionsApiFetchParamCreator = function (configuration?: Configuration) { return { /** - * - * @param {number} solutionId + * + * @param {number} solutionId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7479,8 +7779,8 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -7495,9 +7795,9 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura }; }, /** - * - * @param {number} [taskId] - * @param {number} [solutionId] + * + * @param {number} [taskId] + * @param {number} [solutionId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7511,8 +7811,8 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -7535,8 +7835,8 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura }; }, /** - * - * @param {number} solutionId + * + * @param {number} solutionId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7555,8 +7855,8 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -7571,8 +7871,8 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura }; }, /** - * - * @param {number} solutionId + * + * @param {number} solutionId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7591,8 +7891,8 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -7607,9 +7907,9 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura }; }, /** - * - * @param {number} taskId - * @param {string} studentId + * + * @param {number} taskId + * @param {string} studentId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7633,8 +7933,8 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -7649,12 +7949,13 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura }; }, /** - * - * @param {number} taskId + * + * @param {number} taskId + * @param {string} [secondMentorId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - solutionsGetTaskSolutionsPageData(taskId: number, options: any = {}): FetchArgs { + solutionsGetTaskSolutionsPageData(taskId: number, secondMentorId?: string, options: any = {}): FetchArgs { // verify required parameter 'taskId' is not null or undefined if (taskId === null || taskId === undefined) { throw new RequiredError('taskId','Required parameter taskId was null or undefined when calling solutionsGetTaskSolutionsPageData.'); @@ -7669,11 +7970,15 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } + if (secondMentorId !== undefined) { + localVarQueryParameter['secondMentorId'] = secondMentorId; + } + localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 localVarUrlObj.search = null; @@ -7685,8 +7990,8 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura }; }, /** - * - * @param {number} [taskId] + * + * @param {number} [taskId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7700,8 +8005,8 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -7720,8 +8025,8 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura }; }, /** - * - * @param {number} taskId + * + * @param {number} taskId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7740,8 +8045,8 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -7756,8 +8061,8 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura }; }, /** - * - * @param {number} solutionId + * + * @param {number} solutionId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7776,8 +8081,8 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -7792,9 +8097,50 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura }; }, /** - * - * @param {number} taskId - * @param {SolutionViewModel} [body] + * + * @param {number} courseId + * @param {PostAutomatedSolutionModel} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + solutionsPostAutomatedSolution(courseId: number, body?: PostAutomatedSolutionModel, options: any = {}): FetchArgs { + // verify required parameter 'courseId' is not null or undefined + if (courseId === null || courseId === undefined) { + throw new RequiredError('courseId','Required parameter courseId was null or undefined when calling solutionsPostAutomatedSolution.'); + } + const localVarPath = `/api/Solutions/automated/{courseId}` + .replace(`{${"courseId"}}`, encodeURIComponent(String(courseId))); + const localVarUrlObj = url.parse(localVarPath, true); + const localVarRequestOptions = Object.assign({ method: 'POST' }, options); + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + if (configuration && configuration.apiKey) { + const localVarApiKeyValue = typeof configuration.apiKey === 'function' + ? configuration.apiKey("Authorization") + : configuration.apiKey; + localVarHeaderParameter["Authorization"] = localVarApiKeyValue; + } + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); + // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 + localVarUrlObj.search = null; + localVarRequestOptions.headers = Object.assign({}, localVarHeaderParameter, options.headers); + const needsSerialization = ("PostAutomatedSolutionModel" !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; + localVarRequestOptions.body = needsSerialization ? JSON.stringify(body || {}) : (body || ""); + + return { + url: url.format(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @param {number} taskId + * @param {SolutionViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7813,12 +8159,12 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -7833,13 +8179,13 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura }; }, /** - * - * @param {number} taskId - * @param {SolutionViewModel} [body] + * + * @param {number} taskId + * @param {PostSolutionModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - solutionsPostSolution(taskId: number, body?: SolutionViewModel, options: any = {}): FetchArgs { + solutionsPostSolution(taskId: number, body?: PostSolutionModel, options: any = {}): FetchArgs { // verify required parameter 'taskId' is not null or undefined if (taskId === null || taskId === undefined) { throw new RequiredError('taskId','Required parameter taskId was null or undefined when calling solutionsPostSolution.'); @@ -7854,18 +8200,18 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 localVarUrlObj.search = null; localVarRequestOptions.headers = Object.assign({}, localVarHeaderParameter, options.headers); - const needsSerialization = ("SolutionViewModel" !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; + const needsSerialization = ("PostSolutionModel" !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; localVarRequestOptions.body = needsSerialization ? JSON.stringify(body || {}) : (body || ""); return { @@ -7874,9 +8220,9 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura }; }, /** - * - * @param {number} solutionId - * @param {RateSolutionModel} [body] + * + * @param {number} solutionId + * @param {RateSolutionModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7895,12 +8241,12 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -7924,8 +8270,8 @@ export const SolutionsApiFetchParamCreator = function (configuration?: Configura export const SolutionsApiFp = function(configuration?: Configuration) { return { /** - * - * @param {number} solutionId + * + * @param {number} solutionId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7942,9 +8288,9 @@ export const SolutionsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} [taskId] - * @param {number} [solutionId] + * + * @param {number} [taskId] + * @param {number} [solutionId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7961,8 +8307,8 @@ export const SolutionsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} solutionId + * + * @param {number} solutionId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7979,8 +8325,8 @@ export const SolutionsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} solutionId + * + * @param {number} solutionId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -7997,9 +8343,9 @@ export const SolutionsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} taskId - * @param {string} studentId + * + * @param {number} taskId + * @param {string} studentId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8016,13 +8362,14 @@ export const SolutionsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} taskId + * + * @param {number} taskId + * @param {string} [secondMentorId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - solutionsGetTaskSolutionsPageData(taskId: number, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { - const localVarFetchArgs = SolutionsApiFetchParamCreator(configuration).solutionsGetTaskSolutionsPageData(taskId, options); + solutionsGetTaskSolutionsPageData(taskId: number, secondMentorId?: string, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { + const localVarFetchArgs = SolutionsApiFetchParamCreator(configuration).solutionsGetTaskSolutionsPageData(taskId, secondMentorId, options); return (fetch: FetchAPI = isomorphicFetch, basePath: string = BASE_PATH) => { return fetch(basePath + localVarFetchArgs.url, localVarFetchArgs.options).then((response) => { if (response.status >= 200 && response.status < 300) { @@ -8034,8 +8381,8 @@ export const SolutionsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} [taskId] + * + * @param {number} [taskId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8052,8 +8399,8 @@ export const SolutionsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} taskId + * + * @param {number} taskId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8070,8 +8417,8 @@ export const SolutionsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} solutionId + * + * @param {number} solutionId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8088,9 +8435,28 @@ export const SolutionsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} taskId - * @param {SolutionViewModel} [body] + * + * @param {number} courseId + * @param {PostAutomatedSolutionModel} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + solutionsPostAutomatedSolution(courseId: number, body?: PostAutomatedSolutionModel, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { + const localVarFetchArgs = SolutionsApiFetchParamCreator(configuration).solutionsPostAutomatedSolution(courseId, body, options); + return (fetch: FetchAPI = isomorphicFetch, basePath: string = BASE_PATH) => { + return fetch(basePath + localVarFetchArgs.url, localVarFetchArgs.options).then((response) => { + if (response.status >= 200 && response.status < 300) { + return response; + } else { + throw response; + } + }); + }; + }, + /** + * + * @param {number} taskId + * @param {SolutionViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8107,13 +8473,13 @@ export const SolutionsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} taskId - * @param {SolutionViewModel} [body] + * + * @param {number} taskId + * @param {PostSolutionModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - solutionsPostSolution(taskId: number, body?: SolutionViewModel, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { + solutionsPostSolution(taskId: number, body?: PostSolutionModel, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { const localVarFetchArgs = SolutionsApiFetchParamCreator(configuration).solutionsPostSolution(taskId, body, options); return (fetch: FetchAPI = isomorphicFetch, basePath: string = BASE_PATH) => { return fetch(basePath + localVarFetchArgs.url, localVarFetchArgs.options).then((response) => { @@ -8126,9 +8492,9 @@ export const SolutionsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} solutionId - * @param {RateSolutionModel} [body] + * + * @param {number} solutionId + * @param {RateSolutionModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8154,8 +8520,8 @@ export const SolutionsApiFp = function(configuration?: Configuration) { export const SolutionsApiFactory = function (configuration?: Configuration, fetch?: FetchAPI, basePath?: string) { return { /** - * - * @param {number} solutionId + * + * @param {number} solutionId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8163,9 +8529,9 @@ export const SolutionsApiFactory = function (configuration?: Configuration, fetc return SolutionsApiFp(configuration).solutionsDeleteSolution(solutionId, options)(fetch, basePath); }, /** - * - * @param {number} [taskId] - * @param {number} [solutionId] + * + * @param {number} [taskId] + * @param {number} [solutionId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8173,8 +8539,8 @@ export const SolutionsApiFactory = function (configuration?: Configuration, fetc return SolutionsApiFp(configuration).solutionsGetSolutionAchievement(taskId, solutionId, options)(fetch, basePath); }, /** - * - * @param {number} solutionId + * + * @param {number} solutionId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8182,8 +8548,8 @@ export const SolutionsApiFactory = function (configuration?: Configuration, fetc return SolutionsApiFp(configuration).solutionsGetSolutionActuality(solutionId, options)(fetch, basePath); }, /** - * - * @param {number} solutionId + * + * @param {number} solutionId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8191,9 +8557,9 @@ export const SolutionsApiFactory = function (configuration?: Configuration, fetc return SolutionsApiFp(configuration).solutionsGetSolutionById(solutionId, options)(fetch, basePath); }, /** - * - * @param {number} taskId - * @param {string} studentId + * + * @param {number} taskId + * @param {string} studentId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8201,17 +8567,18 @@ export const SolutionsApiFactory = function (configuration?: Configuration, fetc return SolutionsApiFp(configuration).solutionsGetStudentSolution(taskId, studentId, options)(fetch, basePath); }, /** - * - * @param {number} taskId + * + * @param {number} taskId + * @param {string} [secondMentorId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - solutionsGetTaskSolutionsPageData(taskId: number, options?: any) { - return SolutionsApiFp(configuration).solutionsGetTaskSolutionsPageData(taskId, options)(fetch, basePath); + solutionsGetTaskSolutionsPageData(taskId: number, secondMentorId?: string, options?: any) { + return SolutionsApiFp(configuration).solutionsGetTaskSolutionsPageData(taskId, secondMentorId, options)(fetch, basePath); }, /** - * - * @param {number} [taskId] + * + * @param {number} [taskId] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8219,8 +8586,8 @@ export const SolutionsApiFactory = function (configuration?: Configuration, fetc return SolutionsApiFp(configuration).solutionsGetUnratedSolutions(taskId, options)(fetch, basePath); }, /** - * - * @param {number} taskId + * + * @param {number} taskId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8228,8 +8595,8 @@ export const SolutionsApiFactory = function (configuration?: Configuration, fetc return SolutionsApiFp(configuration).solutionsGiveUp(taskId, options)(fetch, basePath); }, /** - * - * @param {number} solutionId + * + * @param {number} solutionId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8237,9 +8604,19 @@ export const SolutionsApiFactory = function (configuration?: Configuration, fetc return SolutionsApiFp(configuration).solutionsMarkSolution(solutionId, options)(fetch, basePath); }, /** - * - * @param {number} taskId - * @param {SolutionViewModel} [body] + * + * @param {number} courseId + * @param {PostAutomatedSolutionModel} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + solutionsPostAutomatedSolution(courseId: number, body?: PostAutomatedSolutionModel, options?: any) { + return SolutionsApiFp(configuration).solutionsPostAutomatedSolution(courseId, body, options)(fetch, basePath); + }, + /** + * + * @param {number} taskId + * @param {SolutionViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8247,19 +8624,19 @@ export const SolutionsApiFactory = function (configuration?: Configuration, fetc return SolutionsApiFp(configuration).solutionsPostEmptySolutionWithRate(taskId, body, options)(fetch, basePath); }, /** - * - * @param {number} taskId - * @param {SolutionViewModel} [body] + * + * @param {number} taskId + * @param {PostSolutionModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - solutionsPostSolution(taskId: number, body?: SolutionViewModel, options?: any) { + solutionsPostSolution(taskId: number, body?: PostSolutionModel, options?: any) { return SolutionsApiFp(configuration).solutionsPostSolution(taskId, body, options)(fetch, basePath); }, /** - * - * @param {number} solutionId - * @param {RateSolutionModel} [body] + * + * @param {number} solutionId + * @param {RateSolutionModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8277,8 +8654,8 @@ export const SolutionsApiFactory = function (configuration?: Configuration, fetc */ export class SolutionsApi extends BaseAPI { /** - * - * @param {number} solutionId + * + * @param {number} solutionId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof SolutionsApi @@ -8288,9 +8665,9 @@ export class SolutionsApi extends BaseAPI { } /** - * - * @param {number} [taskId] - * @param {number} [solutionId] + * + * @param {number} [taskId] + * @param {number} [solutionId] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof SolutionsApi @@ -8300,8 +8677,8 @@ export class SolutionsApi extends BaseAPI { } /** - * - * @param {number} solutionId + * + * @param {number} solutionId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof SolutionsApi @@ -8311,8 +8688,8 @@ export class SolutionsApi extends BaseAPI { } /** - * - * @param {number} solutionId + * + * @param {number} solutionId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof SolutionsApi @@ -8322,9 +8699,9 @@ export class SolutionsApi extends BaseAPI { } /** - * - * @param {number} taskId - * @param {string} studentId + * + * @param {number} taskId + * @param {string} studentId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof SolutionsApi @@ -8334,19 +8711,20 @@ export class SolutionsApi extends BaseAPI { } /** - * - * @param {number} taskId + * + * @param {number} taskId + * @param {string} [secondMentorId] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof SolutionsApi */ - public solutionsGetTaskSolutionsPageData(taskId: number, options?: any) { - return SolutionsApiFp(this.configuration).solutionsGetTaskSolutionsPageData(taskId, options)(this.fetch, this.basePath); + public solutionsGetTaskSolutionsPageData(taskId: number, secondMentorId?: string, options?: any) { + return SolutionsApiFp(this.configuration).solutionsGetTaskSolutionsPageData(taskId, secondMentorId, options)(this.fetch, this.basePath); } /** - * - * @param {number} [taskId] + * + * @param {number} [taskId] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof SolutionsApi @@ -8356,8 +8734,8 @@ export class SolutionsApi extends BaseAPI { } /** - * - * @param {number} taskId + * + * @param {number} taskId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof SolutionsApi @@ -8367,8 +8745,8 @@ export class SolutionsApi extends BaseAPI { } /** - * - * @param {number} solutionId + * + * @param {number} solutionId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof SolutionsApi @@ -8378,9 +8756,21 @@ export class SolutionsApi extends BaseAPI { } /** - * - * @param {number} taskId - * @param {SolutionViewModel} [body] + * + * @param {number} courseId + * @param {PostAutomatedSolutionModel} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SolutionsApi + */ + public solutionsPostAutomatedSolution(courseId: number, body?: PostAutomatedSolutionModel, options?: any) { + return SolutionsApiFp(this.configuration).solutionsPostAutomatedSolution(courseId, body, options)(this.fetch, this.basePath); + } + + /** + * + * @param {number} taskId + * @param {SolutionViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof SolutionsApi @@ -8390,21 +8780,21 @@ export class SolutionsApi extends BaseAPI { } /** - * - * @param {number} taskId - * @param {SolutionViewModel} [body] + * + * @param {number} taskId + * @param {PostSolutionModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof SolutionsApi */ - public solutionsPostSolution(taskId: number, body?: SolutionViewModel, options?: any) { + public solutionsPostSolution(taskId: number, body?: PostSolutionModel, options?: any) { return SolutionsApiFp(this.configuration).solutionsPostSolution(taskId, body, options)(this.fetch, this.basePath); } /** - * - * @param {number} solutionId - * @param {RateSolutionModel} [body] + * + * @param {number} solutionId + * @param {RateSolutionModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof SolutionsApi @@ -8421,8 +8811,8 @@ export class SolutionsApi extends BaseAPI { export const StatisticsApiFetchParamCreator = function (configuration?: Configuration) { return { /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8441,8 +8831,8 @@ export const StatisticsApiFetchParamCreator = function (configuration?: Configur // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -8457,8 +8847,8 @@ export const StatisticsApiFetchParamCreator = function (configuration?: Configur }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8477,8 +8867,8 @@ export const StatisticsApiFetchParamCreator = function (configuration?: Configur // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -8493,8 +8883,8 @@ export const StatisticsApiFetchParamCreator = function (configuration?: Configur }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8513,8 +8903,8 @@ export const StatisticsApiFetchParamCreator = function (configuration?: Configur // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -8538,8 +8928,8 @@ export const StatisticsApiFetchParamCreator = function (configuration?: Configur export const StatisticsApiFp = function(configuration?: Configuration) { return { /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8556,8 +8946,8 @@ export const StatisticsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8574,8 +8964,8 @@ export const StatisticsApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8601,8 +8991,8 @@ export const StatisticsApiFp = function(configuration?: Configuration) { export const StatisticsApiFactory = function (configuration?: Configuration, fetch?: FetchAPI, basePath?: string) { return { /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8610,8 +9000,8 @@ export const StatisticsApiFactory = function (configuration?: Configuration, fet return StatisticsApiFp(configuration).statisticsGetChartStatistics(courseId, options)(fetch, basePath); }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8619,8 +9009,8 @@ export const StatisticsApiFactory = function (configuration?: Configuration, fet return StatisticsApiFp(configuration).statisticsGetCourseStatistics(courseId, options)(fetch, basePath); }, /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8638,8 +9028,8 @@ export const StatisticsApiFactory = function (configuration?: Configuration, fet */ export class StatisticsApi extends BaseAPI { /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof StatisticsApi @@ -8649,8 +9039,8 @@ export class StatisticsApi extends BaseAPI { } /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof StatisticsApi @@ -8660,8 +9050,8 @@ export class StatisticsApi extends BaseAPI { } /** - * - * @param {number} courseId + * + * @param {number} courseId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof StatisticsApi @@ -8678,7 +9068,7 @@ export class StatisticsApi extends BaseAPI { export const SystemApiFetchParamCreator = function (configuration?: Configuration) { return { /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8692,8 +9082,8 @@ export const SystemApiFetchParamCreator = function (configuration?: Configuratio // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -8717,7 +9107,7 @@ export const SystemApiFetchParamCreator = function (configuration?: Configuratio export const SystemApiFp = function(configuration?: Configuration) { return { /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8743,7 +9133,7 @@ export const SystemApiFp = function(configuration?: Configuration) { export const SystemApiFactory = function (configuration?: Configuration, fetch?: FetchAPI, basePath?: string) { return { /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8761,7 +9151,7 @@ export const SystemApiFactory = function (configuration?: Configuration, fetch?: */ export class SystemApi extends BaseAPI { /** - * + * * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof SystemApi @@ -8778,8 +9168,8 @@ export class SystemApi extends BaseAPI { export const TasksApiFetchParamCreator = function (configuration?: Configuration) { return { /** - * - * @param {AddAnswerForQuestionDto} [body] + * + * @param {AddAnswerForQuestionDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8793,12 +9183,12 @@ export const TasksApiFetchParamCreator = function (configuration?: Configuration // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -8813,8 +9203,8 @@ export const TasksApiFetchParamCreator = function (configuration?: Configuration }; }, /** - * - * @param {AddTaskQuestionDto} [body] + * + * @param {AddTaskQuestionDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8828,12 +9218,12 @@ export const TasksApiFetchParamCreator = function (configuration?: Configuration // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 @@ -8848,13 +9238,13 @@ export const TasksApiFetchParamCreator = function (configuration?: Configuration }; }, /** - * - * @param {number} homeworkId - * @param {CreateTaskViewModel} [body] + * + * @param {number} homeworkId + * @param {PostTaskViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - tasksAddTask(homeworkId: number, body?: CreateTaskViewModel, options: any = {}): FetchArgs { + tasksAddTask(homeworkId: number, body?: PostTaskViewModel, options: any = {}): FetchArgs { // verify required parameter 'homeworkId' is not null or undefined if (homeworkId === null || homeworkId === undefined) { throw new RequiredError('homeworkId','Required parameter homeworkId was null or undefined when calling tasksAddTask.'); @@ -8869,18 +9259,18 @@ export const TasksApiFetchParamCreator = function (configuration?: Configuration // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 localVarUrlObj.search = null; localVarRequestOptions.headers = Object.assign({}, localVarHeaderParameter, options.headers); - const needsSerialization = ("CreateTaskViewModel" !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; + const needsSerialization = ("PostTaskViewModel" !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; localVarRequestOptions.body = needsSerialization ? JSON.stringify(body || {}) : (body || ""); return { @@ -8889,8 +9279,8 @@ export const TasksApiFetchParamCreator = function (configuration?: Configuration }; }, /** - * - * @param {number} taskId + * + * @param {number} taskId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8909,8 +9299,8 @@ export const TasksApiFetchParamCreator = function (configuration?: Configuration // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -8925,8 +9315,8 @@ export const TasksApiFetchParamCreator = function (configuration?: Configuration }; }, /** - * - * @param {number} taskId + * + * @param {number} taskId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8945,8 +9335,38 @@ export const TasksApiFetchParamCreator = function (configuration?: Configuration // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; + localVarHeaderParameter["Authorization"] = localVarApiKeyValue; + } + + localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); + // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 + localVarUrlObj.search = null; + localVarRequestOptions.headers = Object.assign({}, localVarHeaderParameter, options.headers); + + return { + url: url.format(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + tasksGetOpenQuestions(options: any = {}): FetchArgs { + const localVarPath = `/api/Tasks/openQuestions`; + const localVarUrlObj = url.parse(localVarPath, true); + const localVarRequestOptions = Object.assign({ method: 'GET' }, options); + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication Bearer required + if (configuration && configuration.apiKey) { + const localVarApiKeyValue = typeof configuration.apiKey === 'function' + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -8961,8 +9381,8 @@ export const TasksApiFetchParamCreator = function (configuration?: Configuration }; }, /** - * - * @param {number} taskId + * + * @param {number} taskId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -8981,8 +9401,8 @@ export const TasksApiFetchParamCreator = function (configuration?: Configuration // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } @@ -8997,12 +9417,13 @@ export const TasksApiFetchParamCreator = function (configuration?: Configuration }; }, /** - * - * @param {number} taskId + * + * @param {number} taskId + * @param {boolean} [withCriteria] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - tasksGetTask(taskId: number, options: any = {}): FetchArgs { + tasksGetTask(taskId: number, withCriteria?: boolean, options: any = {}): FetchArgs { // verify required parameter 'taskId' is not null or undefined if (taskId === null || taskId === undefined) { throw new RequiredError('taskId','Required parameter taskId was null or undefined when calling tasksGetTask.'); @@ -9017,11 +9438,15 @@ export const TasksApiFetchParamCreator = function (configuration?: Configuration // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } + if (withCriteria !== undefined) { + localVarQueryParameter['withCriteria'] = withCriteria; + } + localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 localVarUrlObj.search = null; @@ -9033,13 +9458,13 @@ export const TasksApiFetchParamCreator = function (configuration?: Configuration }; }, /** - * - * @param {number} taskId - * @param {CreateTaskViewModel} [body] + * + * @param {number} taskId + * @param {PostTaskViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - tasksUpdateTask(taskId: number, body?: CreateTaskViewModel, options: any = {}): FetchArgs { + tasksUpdateTask(taskId: number, body?: PostTaskViewModel, options: any = {}): FetchArgs { // verify required parameter 'taskId' is not null or undefined if (taskId === null || taskId === undefined) { throw new RequiredError('taskId','Required parameter taskId was null or undefined when calling tasksUpdateTask.'); @@ -9054,18 +9479,18 @@ export const TasksApiFetchParamCreator = function (configuration?: Configuration // authentication Bearer required if (configuration && configuration.apiKey) { const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? configuration.apiKey("Authorization") - : configuration.apiKey; + ? configuration.apiKey("Authorization") + : configuration.apiKey; localVarHeaderParameter["Authorization"] = localVarApiKeyValue; } - localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + localVarHeaderParameter['Content-Type'] = 'application/json'; localVarUrlObj.query = Object.assign({}, localVarUrlObj.query, localVarQueryParameter, options.query); // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 localVarUrlObj.search = null; localVarRequestOptions.headers = Object.assign({}, localVarHeaderParameter, options.headers); - const needsSerialization = ("CreateTaskViewModel" !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; + const needsSerialization = ("PostTaskViewModel" !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; localVarRequestOptions.body = needsSerialization ? JSON.stringify(body || {}) : (body || ""); return { @@ -9083,8 +9508,8 @@ export const TasksApiFetchParamCreator = function (configuration?: Configuration export const TasksApiFp = function(configuration?: Configuration) { return { /** - * - * @param {AddAnswerForQuestionDto} [body] + * + * @param {AddAnswerForQuestionDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -9101,8 +9526,8 @@ export const TasksApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {AddTaskQuestionDto} [body] + * + * @param {AddTaskQuestionDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -9119,13 +9544,13 @@ export const TasksApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} homeworkId - * @param {CreateTaskViewModel} [body] + * + * @param {number} homeworkId + * @param {PostTaskViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - tasksAddTask(homeworkId: number, body?: CreateTaskViewModel, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { + tasksAddTask(homeworkId: number, body?: PostTaskViewModel, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { const localVarFetchArgs = TasksApiFetchParamCreator(configuration).tasksAddTask(homeworkId, body, options); return (fetch: FetchAPI = isomorphicFetch, basePath: string = BASE_PATH) => { return fetch(basePath + localVarFetchArgs.url, localVarFetchArgs.options).then((response) => { @@ -9138,8 +9563,8 @@ export const TasksApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} taskId + * + * @param {number} taskId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -9156,8 +9581,8 @@ export const TasksApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} taskId + * + * @param {number} taskId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -9174,8 +9599,25 @@ export const TasksApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} taskId + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + tasksGetOpenQuestions(options?: any): (fetch?: FetchAPI, basePath?: string) => Promise> { + const localVarFetchArgs = TasksApiFetchParamCreator(configuration).tasksGetOpenQuestions(options); + return (fetch: FetchAPI = isomorphicFetch, basePath: string = BASE_PATH) => { + return fetch(basePath + localVarFetchArgs.url, localVarFetchArgs.options).then((response) => { + if (response.status >= 200 && response.status < 300) { + return response.json(); + } else { + throw response; + } + }); + }; + }, + /** + * + * @param {number} taskId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -9192,13 +9634,14 @@ export const TasksApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} taskId + * + * @param {number} taskId + * @param {boolean} [withCriteria] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - tasksGetTask(taskId: number, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { - const localVarFetchArgs = TasksApiFetchParamCreator(configuration).tasksGetTask(taskId, options); + tasksGetTask(taskId: number, withCriteria?: boolean, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { + const localVarFetchArgs = TasksApiFetchParamCreator(configuration).tasksGetTask(taskId, withCriteria, options); return (fetch: FetchAPI = isomorphicFetch, basePath: string = BASE_PATH) => { return fetch(basePath + localVarFetchArgs.url, localVarFetchArgs.options).then((response) => { if (response.status >= 200 && response.status < 300) { @@ -9210,13 +9653,13 @@ export const TasksApiFp = function(configuration?: Configuration) { }; }, /** - * - * @param {number} taskId - * @param {CreateTaskViewModel} [body] + * + * @param {number} taskId + * @param {PostTaskViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - tasksUpdateTask(taskId: number, body?: CreateTaskViewModel, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { + tasksUpdateTask(taskId: number, body?: PostTaskViewModel, options?: any): (fetch?: FetchAPI, basePath?: string) => Promise { const localVarFetchArgs = TasksApiFetchParamCreator(configuration).tasksUpdateTask(taskId, body, options); return (fetch: FetchAPI = isomorphicFetch, basePath: string = BASE_PATH) => { return fetch(basePath + localVarFetchArgs.url, localVarFetchArgs.options).then((response) => { @@ -9238,8 +9681,8 @@ export const TasksApiFp = function(configuration?: Configuration) { export const TasksApiFactory = function (configuration?: Configuration, fetch?: FetchAPI, basePath?: string) { return { /** - * - * @param {AddAnswerForQuestionDto} [body] + * + * @param {AddAnswerForQuestionDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -9247,8 +9690,8 @@ export const TasksApiFactory = function (configuration?: Configuration, fetch?: return TasksApiFp(configuration).tasksAddAnswerForQuestion(body, options)(fetch, basePath); }, /** - * - * @param {AddTaskQuestionDto} [body] + * + * @param {AddTaskQuestionDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -9256,18 +9699,18 @@ export const TasksApiFactory = function (configuration?: Configuration, fetch?: return TasksApiFp(configuration).tasksAddQuestionForTask(body, options)(fetch, basePath); }, /** - * - * @param {number} homeworkId - * @param {CreateTaskViewModel} [body] + * + * @param {number} homeworkId + * @param {PostTaskViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - tasksAddTask(homeworkId: number, body?: CreateTaskViewModel, options?: any) { + tasksAddTask(homeworkId: number, body?: PostTaskViewModel, options?: any) { return TasksApiFp(configuration).tasksAddTask(homeworkId, body, options)(fetch, basePath); }, /** - * - * @param {number} taskId + * + * @param {number} taskId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -9275,8 +9718,8 @@ export const TasksApiFactory = function (configuration?: Configuration, fetch?: return TasksApiFp(configuration).tasksDeleteTask(taskId, options)(fetch, basePath); }, /** - * - * @param {number} taskId + * + * @param {number} taskId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -9284,8 +9727,16 @@ export const TasksApiFactory = function (configuration?: Configuration, fetch?: return TasksApiFp(configuration).tasksGetForEditingTask(taskId, options)(fetch, basePath); }, /** - * - * @param {number} taskId + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + tasksGetOpenQuestions(options?: any) { + return TasksApiFp(configuration).tasksGetOpenQuestions(options)(fetch, basePath); + }, + /** + * + * @param {number} taskId * @param {*} [options] Override http request option. * @throws {RequiredError} */ @@ -9293,22 +9744,23 @@ export const TasksApiFactory = function (configuration?: Configuration, fetch?: return TasksApiFp(configuration).tasksGetQuestionsForTask(taskId, options)(fetch, basePath); }, /** - * - * @param {number} taskId + * + * @param {number} taskId + * @param {boolean} [withCriteria] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - tasksGetTask(taskId: number, options?: any) { - return TasksApiFp(configuration).tasksGetTask(taskId, options)(fetch, basePath); + tasksGetTask(taskId: number, withCriteria?: boolean, options?: any) { + return TasksApiFp(configuration).tasksGetTask(taskId, withCriteria, options)(fetch, basePath); }, /** - * - * @param {number} taskId - * @param {CreateTaskViewModel} [body] + * + * @param {number} taskId + * @param {PostTaskViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - tasksUpdateTask(taskId: number, body?: CreateTaskViewModel, options?: any) { + tasksUpdateTask(taskId: number, body?: PostTaskViewModel, options?: any) { return TasksApiFp(configuration).tasksUpdateTask(taskId, body, options)(fetch, basePath); }, }; @@ -9322,8 +9774,8 @@ export const TasksApiFactory = function (configuration?: Configuration, fetch?: */ export class TasksApi extends BaseAPI { /** - * - * @param {AddAnswerForQuestionDto} [body] + * + * @param {AddAnswerForQuestionDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof TasksApi @@ -9333,8 +9785,8 @@ export class TasksApi extends BaseAPI { } /** - * - * @param {AddTaskQuestionDto} [body] + * + * @param {AddTaskQuestionDto} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof TasksApi @@ -9344,20 +9796,20 @@ export class TasksApi extends BaseAPI { } /** - * - * @param {number} homeworkId - * @param {CreateTaskViewModel} [body] + * + * @param {number} homeworkId + * @param {PostTaskViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof TasksApi */ - public tasksAddTask(homeworkId: number, body?: CreateTaskViewModel, options?: any) { + public tasksAddTask(homeworkId: number, body?: PostTaskViewModel, options?: any) { return TasksApiFp(this.configuration).tasksAddTask(homeworkId, body, options)(this.fetch, this.basePath); } /** - * - * @param {number} taskId + * + * @param {number} taskId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof TasksApi @@ -9367,8 +9819,8 @@ export class TasksApi extends BaseAPI { } /** - * - * @param {number} taskId + * + * @param {number} taskId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof TasksApi @@ -9378,8 +9830,18 @@ export class TasksApi extends BaseAPI { } /** - * - * @param {number} taskId + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof TasksApi + */ + public tasksGetOpenQuestions(options?: any) { + return TasksApiFp(this.configuration).tasksGetOpenQuestions(options)(this.fetch, this.basePath); + } + + /** + * + * @param {number} taskId * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof TasksApi @@ -9389,27 +9851,27 @@ export class TasksApi extends BaseAPI { } /** - * - * @param {number} taskId + * + * @param {number} taskId + * @param {boolean} [withCriteria] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof TasksApi */ - public tasksGetTask(taskId: number, options?: any) { - return TasksApiFp(this.configuration).tasksGetTask(taskId, options)(this.fetch, this.basePath); + public tasksGetTask(taskId: number, withCriteria?: boolean, options?: any) { + return TasksApiFp(this.configuration).tasksGetTask(taskId, withCriteria, options)(this.fetch, this.basePath); } /** - * - * @param {number} taskId - * @param {CreateTaskViewModel} [body] + * + * @param {number} taskId + * @param {PostTaskViewModel} [body] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof TasksApi */ - public tasksUpdateTask(taskId: number, body?: CreateTaskViewModel, options?: any) { + public tasksUpdateTask(taskId: number, body?: PostTaskViewModel, options?: any) { return TasksApiFp(this.configuration).tasksUpdateTask(taskId, body, options)(this.fetch, this.basePath); } } - diff --git a/hwproj.front/src/components/Auth/Login.tsx b/hwproj.front/src/components/Auth/Login.tsx index 91d3e33be..1f9e7a3ce 100644 --- a/hwproj.front/src/components/Auth/Login.tsx +++ b/hwproj.front/src/components/Auth/Login.tsx @@ -1,17 +1,15 @@ import React, {FC, FormEvent} from "react"; -import Avatar from '@material-ui/core/Avatar'; -import LockOutlinedIcon from '@material-ui/icons/LockOutlined' import {Navigate, Link, useSearchParams} from "react-router-dom"; import {TextField, Button, Typography} from "@material-ui/core"; import Grid from '@material-ui/core/Grid'; import ApiSingleton from "../../api/ApiSingleton"; import "./Styles/Login.css"; import {useState} from "react"; -import {LoginViewModel} from "../../api/" +import {LoginViewModel} from "@/api" import {makeStyles} from '@material-ui/core/styles'; import Container from '@material-ui/core/Container'; import ValidationUtils from "../Utils/ValidationUtils"; -import {Card, CardContent} from "@mui/material"; +import {Alert, Card, CardContent, Stack} from "@mui/material"; import {DotLottieReact} from "@lottiefiles/dotlottie-react"; interface LoginProps { @@ -26,11 +24,6 @@ interface ILoginState { } const useStyles = makeStyles((theme) => ({ - paper: { - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - }, login: { marginTop: '16px', width: '100%', @@ -47,11 +40,6 @@ const useStyles = makeStyles((theme) => ({ }, button: { marginTop: theme.spacing(2) - }, - clickable_text: { - marginTop: theme.spacing(1), - textAlign: "center", - color: "#949494" } })) @@ -139,20 +127,17 @@ const Login: FC = (props) => { src="https://lottie.host/919997f6-e82f-4995-b17d-bb3dad2376be/jDvgCK2W1q.lottie" autoplay /> - + - - - - - - Войти - - {loginState.error && ( -

- {loginState.error} -

- )} + + + + Привет 👋, рады Вас видеть + + + {loginState.error && loginState.error.length > 0 && + {loginState.error} + }
handleSubmit(e)} className={classes.form}> @@ -181,6 +166,11 @@ const Login: FC = (props) => { value={loginState.password} onChange={handleChangePassword} /> + + + Забыли пароль? + + -
- - - Забыли пароль? + + + Впервые тут? + + + + Регистрация + - +
diff --git a/hwproj.front/src/components/Auth/PasswordRecovery.tsx b/hwproj.front/src/components/Auth/PasswordRecovery.tsx index cd319b573..8c34787a6 100644 --- a/hwproj.front/src/components/Auth/PasswordRecovery.tsx +++ b/hwproj.front/src/components/Auth/PasswordRecovery.tsx @@ -10,6 +10,7 @@ import {makeStyles} from '@material-ui/core/styles'; import Container from '@material-ui/core/Container'; import {Alert, AlertTitle} from "@mui/material"; import ValidationUtils from "../Utils/ValidationUtils"; +import { useLocation } from "react-router-dom"; interface IRecoverState { email: string; @@ -44,10 +45,10 @@ const useStyles = makeStyles((theme) => ({ })) const PasswordRecovery: FC = () => { - + const location = useLocation(); const classes = useStyles() const [recoverState, setRecoverState] = useState({ - email: '', + email: location.state?.email || '', error: [], isSuccess: false, }) @@ -127,7 +128,7 @@ const PasswordRecovery: FC = () => { label="Электронная почта" variant="outlined" margin="normal" - name={recoverState.email} + value={recoverState.email} onChange={handleChangeEmail} error={emailError !== ""} helperText={emailError} diff --git a/hwproj.front/src/components/Auth/Register.tsx b/hwproj.front/src/components/Auth/Register.tsx index e1cd06605..fc27eaff2 100644 --- a/hwproj.front/src/components/Auth/Register.tsx +++ b/hwproj.front/src/components/Auth/Register.tsx @@ -64,7 +64,14 @@ const Register: FC = () => { } e.preventDefault() try { - const result = await ApiSingleton.authService.register(registerState) + const registerModel: RegisterViewModel = + { + email: registerState.email.trim(), + name: registerState.name.trim(), + surname: registerState.surname.trim(), + middleName: registerState.middleName?.trim() || "" + } + const result = await ApiSingleton.authService.register(registerModel) setCommonState((prevState) => ({ ...prevState, error: result!.error!, diff --git a/hwproj.front/src/components/Common/HomeworkTags.tsx b/hwproj.front/src/components/Common/HomeworkTags.tsx index 82a584ab3..5c51be04f 100644 --- a/hwproj.front/src/components/Common/HomeworkTags.tsx +++ b/hwproj.front/src/components/Common/HomeworkTags.tsx @@ -9,7 +9,7 @@ export const DefaultTags = [TestTag, BonusTag, GroupWorkTag] export const isTestWork = (tagsOwner: { tags?: string[] }) => tagsOwner.tags?.includes(TestTag) ?? false export const isBonusWork = (tagsOwner: { tags?: string[] }) => tagsOwner.tags?.includes(BonusTag) ?? false -const TestTip: FC = () => тест +export const TestTip: FC = () => тест const BonusTip: FC = () => бонус export const getTip = (tagsOwner: { tags?: string[] }) => { diff --git a/hwproj.front/src/components/Common/MarkdownEditor.tsx b/hwproj.front/src/components/Common/MarkdownEditor.tsx index 71864698b..388869850 100644 --- a/hwproj.front/src/components/Common/MarkdownEditor.tsx +++ b/hwproj.front/src/components/Common/MarkdownEditor.tsx @@ -1,5 +1,5 @@ -import {ChangeEvent, FC} from "react"; -import MDEditor from "@uiw/react-md-editor"; +import {FC} from "react"; +import MDEditor, { PreviewType } from "@uiw/react-md-editor"; import {getCommands, getExtraCommands} from "./Styles/MarkdownEditorCommands.ru"; import rehypeSanitize, {defaultSchema} from 'rehype-sanitize'; import * as React from "react"; @@ -8,12 +8,15 @@ import "@uiw/react-md-editor/markdown-editor.css"; import "@uiw/react-markdown-preview/markdown.css"; import "./Styles/MarkdownEditor.css"; import {Schema} from "rehype-sanitize/lib"; +import remarkMath from 'remark-math'; +import rehypeKatex from 'rehype-katex'; interface MarkdownEditorProps { label: string; maxHeight?: number; height?: number; value: string; + previewMode?: PreviewType onChange: (value: string) => void; } @@ -25,12 +28,27 @@ interface MarkdownPreviewProps { const customRehypeSanitizeSchema: Schema = { ...defaultSchema, - tagNames: [...defaultSchema.tagNames!, 'code', 'span'], + tagNames: [ + ...(defaultSchema.tagNames || []), + // Базовые HTML-теги (разметка и подсветка кода) + 'span', 'code', + // MathML Core: + 'math', 'mrow', 'mi', 'mo', 'mn', 'msub', 'msup', 'mfrac', 'msqrt', + // MathML Advanced: + 'maction', 'maligngroup', 'malignmark', 'menclose', 'merror', + 'mfenced', 'mi', 'mlongdiv', 'mmultiscripts', 'mover', + 'mpadded', 'mphantom', 'mroot', 'ms', 'mscarries', 'mscarry', + 'msgroup', 'msline', 'mspace', 'msrow', 'mstack', 'mstyle', + 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', + // Аннотации: + 'semantics', 'annotation', 'annotation-xml' + ], attributes: { ...defaultSchema.attributes, - code: ['className'], - span: ['className'], - }, + '*': ['className'], // Стилизация KaTeX и подсветка синтаксиса + math: ['xmlns'], // Пространство имен MathML + annotation: ['encoding'], // Формат аннотации + } }; const MarkdownPreview: FC = (props) => = (props) => const MarkdownEditor: FC = (props) => { - const handleChange = (value: string | undefined, event?: ChangeEvent) => { - if (value !== undefined) { - props.onChange(value!); - } + const handleChange = (value: string | undefined) => { + if (value !== undefined) props.onChange(value); }; return ( -
+
= (props) => { onChange={handleChange} previewOptions={{ className: "markdown-preview", - rehypePlugins: [[rehypeSanitize, customRehypeSanitizeSchema]] + remarkPlugins: [remarkMath], + rehypePlugins: [ + [rehypeKatex as any, { output: 'mathml' }], + [rehypeSanitize, customRehypeSanitizeSchema] + ], }} maxHeight={props.maxHeight ?? 400} height={props.height ?? 230} - textareaProps={{ - placeholder: props.label - }} - preview="edit" + textareaProps={{placeholder: props.label}} + preview={props.previewMode || "edit"} />
); diff --git a/hwproj.front/src/components/Common/MentorsList.tsx b/hwproj.front/src/components/Common/MentorsList.tsx index f07961a18..68adeb04a 100644 --- a/hwproj.front/src/components/Common/MentorsList.tsx +++ b/hwproj.front/src/components/Common/MentorsList.tsx @@ -1,8 +1,8 @@ import {FC} from "react"; -import {AccountDataDto} from "../../api"; +import {AccountDataDto} from "@/api"; import {Typography} from "@material-ui/core"; import * as React from "react"; -import {Badge, Stack, Tooltip} from "@mui/material"; +import {Stack, Tooltip} from "@mui/material"; const MentorsList: FC<{ mentors: AccountDataDto[] @@ -17,19 +17,19 @@ const MentorsList: FC<{ {mentorsToShow.map(t => `${t.name} ${t.surname}`).join(", ")} - {mentorsToHide.length > 0 && + {mentorsToHide.length > 0 && + {mentorsToHide.map((t, index) =>
{`${t.name} ${t.surname}`} {t.companyName}
)}
}> - -
- - } + + и ещё {mentorsToHide.length} + + } } diff --git a/hwproj.front/src/components/Common/StudentTags.ts b/hwproj.front/src/components/Common/StudentTags.ts new file mode 100644 index 000000000..8d96b7ebe --- /dev/null +++ b/hwproj.front/src/components/Common/StudentTags.ts @@ -0,0 +1 @@ +export const RemovedFromCourseTag = "Удален с курса" \ No newline at end of file diff --git a/hwproj.front/src/components/Common/Styles/MarkdownEditorCommands.ru.tsx b/hwproj.front/src/components/Common/Styles/MarkdownEditorCommands.ru.tsx new file mode 100644 index 000000000..6f2cd354d --- /dev/null +++ b/hwproj.front/src/components/Common/Styles/MarkdownEditorCommands.ru.tsx @@ -0,0 +1,226 @@ +import {executeCommand, ExecuteState, ICommand, selectWord, TextAreaTextApi} from '@uiw/react-md-editor'; +import { + divider, + group, + code as codeInit, + codeBlock as codeBlockInit, + comment as commentInit, + fullscreen as fullscreenInit, + hr as hrInit, + image as imageInit, + italic as italicInit, + bold as boldInit, + link as linkInit, + checkedListCommand as checkedListCommandInit, + orderedListCommand as orderedListCommandInit, + unorderedListCommand as unorderedListCommandInit, + codeEdit as codeEditInit, + codeLive as codeLiveInit, + codePreview as codePreviewInit, + quote as quoteInit, + strikethrough as strikethroughInit, + issue as issueInit, + title as titleInit, + title1 as title1Init, + title2 as title2Init, + title3 as title3Init, + title4 as title4Init, + title5 as title5Init, + title6 as title6Init, + table as tableInit, + help as helpInit +} from '@uiw/react-md-editor'; + +let bold: ICommand = { + ...boldInit, + buttonProps: {'aria-label': 'Выделить жирным (ctrl + b)', title: 'Выделить жирным (ctrl + b)'}, +}; +let code: ICommand = { + ...codeInit, + buttonProps: {'aria-label': 'Вставить код (ctrl + j)', title: 'Вставить код (ctrl + j)'} +}; +let codeBlock: ICommand = { + ...codeBlockInit, + buttonProps: { + 'aria-label': 'Вставить блок кода (ctrl + shift + j)', + title: 'Вставить блок кода (ctrl + shift + j)' + }, +}; +let comment: ICommand = { + ...commentInit, + buttonProps: {'aria-label': 'Закомментировать (ctrl + /)', title: 'Закомментировать (ctrl + /)'}, +}; +let fullscreen: ICommand = { + ...fullscreenInit, + buttonProps: {'aria-label': 'На весь экран (ctrl + 0)', title: 'На весь экран (ctrl + 0)'}, +}; +let hr: ICommand = { + ...hrInit, buttonProps: { + 'aria-label': 'Вставить горизонтальную линию (ctrl + h)', + title: 'Вставить горизонтальную линию (ctrl + h)' + } +}; +let image: ICommand = { + ...imageInit, + buttonProps: {'aria-label': 'Добавить изображение (ctrl + k)', title: 'Добавить изображение (ctrl + k)'}, +}; +let italic: ICommand = { + ...italicInit, + buttonProps: {'aria-label': 'Выделить курсивом (ctrl + i)', title: 'Выделить курсивом (ctrl + i)'}, +}; +let link: ICommand = { + ...linkInit, + buttonProps: {'aria-label': 'Добавить ссылку (ctrl + l)', title: 'Добавить ссылку (ctrl + l)'} +}; +let checkedListCommand: ICommand = { + ...checkedListCommandInit, + buttonProps: {'aria-label': 'Добавить список (ctrl + shift + c)', title: 'Добавить список (ctrl + shift + c)'}, +}; +let orderedListCommand: ICommand = { + ...orderedListCommandInit, + buttonProps: { + 'aria-label': 'Добавить нумерованный список (ctrl + shift + o)', + title: 'Добавить нумерованный список (ctrl + shift + o)' + }, +}; +let unorderedListCommand: ICommand = { + ...unorderedListCommandInit, + buttonProps: { + 'aria-label': 'Добавить маркированный список (ctrl + shift + u)', + title: 'Добавить маркированный список (ctrl + shift + u)', + }, +}; +let codeEdit: ICommand = { + ...codeEditInit, + buttonProps: {'aria-label': 'В режим редактирования (ctrl + 7)', title: 'В режим редактирования (ctrl + 7)'}, +}; +let codeLive: ICommand = { + ...codeLiveInit, + buttonProps: {'aria-label': 'В дублированный режим (ctrl + 8)', title: 'В дублированный режим (ctrl + 8)'}, +}; +let codePreview: ICommand = { + ...codePreviewInit, + buttonProps: {'aria-label': 'В режим превью (ctrl + 9)', title: 'В режим превью (ctrl + 9)'}, +}; +let quote: ICommand = { + ...quoteInit, + buttonProps: {'aria-label': 'Вставить цитату (ctrl + 9)', title: 'Вставить цитату (ctrl + 9)'}, +}; +let strikethrough: ICommand = { + ...strikethroughInit, + buttonProps: { + 'aria-label': 'Выделить зачеркнутым (ctrl + shift + x)', + title: 'Выделить зачеркнутым (ctrl + shift + x)', + }, +}; +let title: ICommand = { + ...titleInit, + buttonProps: {'aria-label': 'Вставить заголовок (ctrl + 1)', title: 'Вставить заголовок (ctrl + 1)'}, +}; +let title1: ICommand = { + ...title1Init, + buttonProps: {'aria-label': 'Вставить заголовок 1 (ctrl + 1)', title: 'Вставить заголовок 1 (ctrl + 1)'}, +}; +let title2: ICommand = { + ...title2Init, + buttonProps: {'aria-label': 'Вставить заголовок 2 (ctrl + 2)', title: 'Вставить заголовок 2 (ctrl + 2)'}, +}; +let title3: ICommand = { + ...title3Init, + buttonProps: {'aria-label': 'Вставить заголовок 3 (ctrl + 3)', title: 'Вставить заголовок 3 (ctrl + 3)'}, +}; +let title4: ICommand = { + ...title4Init, + buttonProps: {'aria-label': 'Вставить заголовок 4 (ctrl + 4)', title: 'Вставить заголовок 4 (ctrl + 4)'}, +}; +let title5: ICommand = { + ...title5Init, + buttonProps: {'aria-label': 'Вставить заголовок 5 (ctrl + 5)', title: 'Вставить заголовок 5 (ctrl + 5)'}, +}; +let title6: ICommand = { + ...title6Init, + buttonProps: {'aria-label': 'Вставить заголовок 6 (ctrl + 6)', title: 'Вставить заголовок 6 (ctrl + 6)'}, +}; +let table: ICommand = {...tableInit, buttonProps: {'aria-label': 'Добавить таблицу', title: 'Добавить таблицу'}}; +let mathFormula: ICommand = { + ...codeInit, + name: 'mathFormula', + keyCommand: 'mathFormula', + shortcuts: 'ctrlcmd+f', + prefix: '$$', + buttonProps: {'aria-label': 'Вставить формулу (ctrl + f)', title: 'Вставить формулу (ctrl + f)'}, + icon: ( + + + ), + execute: (state: ExecuteState, api: TextAreaTextApi) => { + if (state.selectedText.indexOf('\n') === -1) { + codeInit.execute!(state, api) + } + } +}; +let help: ICommand = { + ...helpInit, + buttonProps: {'aria-label': 'Открыть описание Markdown', title: 'Открыть описание Markdown'} +}; + +export const getCommands: () => ICommand[] = () => [ + bold, + italic, + strikethrough, + hr, + group([title1, title2, title3, title4, title5, title6], { + name: 'title', + groupName: 'title', + buttonProps: {'aria-label': 'Вставить заголовок', title: 'Вставить заголовок'}, + }), + divider, + link, + quote, + mathFormula, + code, + codeBlock, + comment, + image, + table, + divider, + unorderedListCommand, + orderedListCommand, + checkedListCommand, + divider, + help, +]; +export const getExtraCommands: () => ICommand[] = () => [codeEdit, codeLive, codePreview, divider, fullscreen]; +export { + title, + title1, + title2, + title3, + title4, + title5, + title6, + bold, + codeBlock, + comment, + italic, + strikethrough, + hr, + group, + divider, + link, + quote, + code, + image, + unorderedListCommand, + orderedListCommand, + checkedListCommand, + table, + help, + codeEdit, + codeLive, + codePreview, + fullscreen, +}; \ No newline at end of file diff --git a/hwproj.front/src/components/Common/Tags.tsx b/hwproj.front/src/components/Common/Tags.tsx index b279f384a..d448bfb02 100644 --- a/hwproj.front/src/components/Common/Tags.tsx +++ b/hwproj.front/src/components/Common/Tags.tsx @@ -3,21 +3,29 @@ import Chip from '@mui/material/Chip'; import Autocomplete from '@mui/material/Autocomplete'; import TextField from '@mui/material/TextField'; import {useState, useEffect, SyntheticEvent} from "react"; +import { Tooltip } from "@mui/material"; interface TagsProps { tags: string[]; + suggestion?: string | undefined; onTagsChange: (tags: string[]) => void; requestTags: () => Promise; isElementSmall: boolean; } -export default function Tags({tags, onTagsChange, requestTags, isElementSmall}: TagsProps) { +export default function Tags({tags, suggestion, onTagsChange, requestTags, isElementSmall}: TagsProps) { const [allTags, setAllTags] = useState([]); + const [showSuggestions, setShowSuggestions] = useState(suggestion !== undefined) + const suggestionTag = "+ " + suggestion useEffect(() => { fetchTags(); }, []); + useEffect(() => { + setShowSuggestions(suggestion !== undefined); + }, [suggestion]) + const fetchTags = async () => { try { const response = await requestTags(); @@ -26,10 +34,15 @@ export default function Tags({tags, onTagsChange, requestTags, isElementSmall}: console.error('Ошибка при получении данных:', error); } }; - const [value, setValue] = useState(tags.filter(t => t !== '')); - const handleOptionSelect = (event: SyntheticEvent, newValue: string[]) => { - setValue(newValue); - onTagsChange(newValue); + const [value, setValue] = useState(tags); + const handleOptionSelect = (event: SyntheticEvent | undefined, newValue: string[], reason: string, details: { + option: string + } | undefined) => { + const formatted = newValue.map(t => t.trim().split(RegExp("\\s+")).join(" ")) + const filtered = formatted.filter(t => t.length > 0 && t !== suggestionTag) + if (reason === "removeOption" && details && details.option === suggestionTag) setShowSuggestions(false) + setValue(filtered); + onTagsChange(filtered); }; return ( - value.map((option: string, index: number) => ( - - )) + value.map((option: string, index: number) => { + return option === suggestionTag ? + + handleOptionSelect(undefined, [...value, suggestion!], "removeOption", {option: option})}/> + : + + }) } renderInput={(params) => ( ) -} \ No newline at end of file +} diff --git a/hwproj.front/src/components/Common/UserAvatar.tsx b/hwproj.front/src/components/Common/UserAvatar.tsx new file mode 100644 index 000000000..62b7ed129 --- /dev/null +++ b/hwproj.front/src/components/Common/UserAvatar.tsx @@ -0,0 +1,17 @@ +import {AccountDataDto} from "@/api"; +import {FC} from "react"; +import AvatarUtils from "@/components/Utils/AvatarUtils"; +import {Avatar} from "@mui/material"; +import {Avatar as Avatarka, generateParams, getThemeNames} from 'avatarka-react'; + +const themes = getThemeNames().filter(x => x !== "geometric") + +export const UserAvatar: FC<{ user: AccountDataDto }> = ({user}) => { + if (user.githubId) return + + const hash = [...user.userId!].reduce((h, c) => Math.imul(h, 31) + c.charCodeAt(0) | 0, 0) >>> 0 + const index = hash % themes.length + const theme = themes[index] + const params = generateParams(theme, user.userId); + return ; +} diff --git a/hwproj.front/src/components/Courses/AddCourseInfo.tsx b/hwproj.front/src/components/Courses/AddCourseInfo.tsx index ead421110..c0b98a1ae 100644 --- a/hwproj.front/src/components/Courses/AddCourseInfo.tsx +++ b/hwproj.front/src/components/Courses/AddCourseInfo.tsx @@ -6,7 +6,7 @@ import { } from "@material-ui/core"; import {LoadingButton} from "@mui/lab"; import {IStepComponentProps} from "./ICreateCourseState"; -import {Alert, Autocomplete, Checkbox, FormControlLabel} from "@mui/material"; +import {Alert, Autocomplete, Checkbox, FormControlLabel, Chip} from "@mui/material"; const AddCourseInfo: FC = ({state, setState}) => { const handleCourseNameChange = (e: ChangeEvent) => { @@ -28,6 +28,17 @@ const AddCourseInfo: FC = ({state, setState}) => { }) }) + const handleGroupSelection = (event: React.SyntheticEvent, newValue: string[]) => { + setState(prev => ({ + ...prev, + selectedGroups: newValue, + isGroupFromList: newValue.some(group => isGroupFromList(group)), + fetchStudents: newValue.every(group => state.groupNames.includes(group)) ? prev.fetchStudents : false, + })); + } + + const isGroupFromList = (group: string) => state.groupNames.includes(group); + return ( @@ -48,7 +59,7 @@ const AddCourseInfo: FC = ({state, setState}) => { setState(prev => ({ ...prev, programName: newValue || '', - groupName: '', + selectedGroups: [], isGroupFromList: false, })); }} @@ -68,52 +79,39 @@ const AddCourseInfo: FC = ({state, setState}) => { студентов из базы студентов университета - {state.programName ? ( - - { - const isFromList = state.groupNames.includes(newValue || ''); - setState(prev => ({ - ...prev, - groupName: newValue || '', - isGroupFromList: isFromList, - fetchStudents: isFromList ? prev.fetchStudents : false, - })); - }} - options={state.groupNames} - loading={state.fetchingGroups} - renderInput={(params) => ( - + ( + + )} + renderTags={(value, getTagProps) => + value.map((option, index) => ( + - )} - fullWidth - /> - - ) : ( - - { - setState(prev => ({ - ...prev, - groupName: e.target.value, - isGroupFromList: false, - fetchStudents: false, - })); - }} - /> - - )} + )) + } + fullWidth + /> + + {state.isGroupFromList && ( = ({state, setState}) => { color="primary" /> } - label="Добавить всех студентов из группы" + label="Добавить студентов из выбранных групп" /> )} @@ -148,7 +146,7 @@ const AddCourseInfo: FC = ({state, setState}) => { color: "#3f51b5", ":hover": {background: "#f7f8fc"}, }} - disabled={!state.courseName || !state.groupName} + disabled={!state.courseName || state.selectedGroups.length === 0} loading={state.courseIsLoading} > Создать курс diff --git a/hwproj.front/src/components/Courses/Course.tsx b/hwproj.front/src/components/Courses/Course.tsx index c10923514..a8744fee3 100644 --- a/hwproj.front/src/components/Courses/Course.tsx +++ b/hwproj.front/src/components/Courses/Course.tsx @@ -1,40 +1,39 @@ import * as React from "react"; -import {useSearchParams} from "react-router-dom"; -import {AccountDataDto, CourseViewModel, FileInfoDTO, HomeworkViewModel, StatisticsCourseMatesModel} from "../../api"; -import CourseHomework from "../Homeworks/CourseHomework"; -import AddHomework from "../Homeworks/AddHomework"; +import {FC, useEffect, useState} from "react"; +import {useNavigate, useParams, useSearchParams} from "react-router-dom"; +import {AccountDataDto, CourseViewModel, HomeworkViewModel, StatisticsCourseMatesModel} from "@/api"; import StudentStats from "./StudentStats"; import NewCourseStudents from "./NewCourseStudents"; import ApiSingleton from "../../api/ApiSingleton"; -import {Button, Grid, Tab, Tabs, Typography, IconButton} from "@material-ui/core"; +import {Button, IconButton, Tab, Tabs} from "@material-ui/core"; import EditIcon from "@material-ui/icons/Edit"; -import {FC, useEffect, useState} from "react"; -import {makeStyles} from "@material-ui/styles"; -import VisibilityIcon from '@material-ui/icons/Visibility'; import { Alert, - AlertTitle, Box, + AlertTitle, + Box, Chip, Dialog, DialogContent, - DialogTitle, ListItemIcon, ListItemText, + DialogTitle, + Grid, + ListItemIcon, + ListItemText, Menu, MenuItem, Stack, - Tooltip + Typography } from "@mui/material"; -import CourseExperimental from "./CourseExperimental"; -import {useParams, useNavigate} from 'react-router-dom'; +import {CourseExperimental} from "./CourseExperimental"; import MentorsList from "../Common/MentorsList"; import LecturerStatistics from "./Statistics/LecturerStatistics"; import AssessmentIcon from '@mui/icons-material/Assessment'; import NameBuilder from "../Utils/NameBuilder"; import {QRCodeSVG} from 'qrcode.react'; -import ErrorsHandler from "components/Utils/ErrorsHandler"; -import {useSnackbar} from 'notistack'; import QrCode2Icon from '@mui/icons-material/QrCode2'; import {MoreVert} from "@mui/icons-material"; import {DotLottieReact} from "@lottiefiles/dotlottie-react"; +import {FilesUploadWaiter} from "@/components/Files/FilesUploadWaiter"; +import {CourseUnitType} from "@/components/Files/CourseUnitType"; type TabValue = "homeworks" | "stats" | "applications" @@ -42,19 +41,13 @@ function isAcceptableTabValue(str: string): str is TabValue { return str === "homeworks" || str === "stats" || str === "applications"; } -interface ICourseProps { - isReadingMode?: boolean; -} - interface ICourseState { isFound: boolean; course: CourseViewModel; courseHomeworks: HomeworkViewModel[]; - createHomework: boolean; mentors: AccountDataDto[]; acceptedStudents: AccountDataDto[]; newStudents: AccountDataDto[]; - isReadingMode: boolean; studentSolutions: StatisticsCourseMatesModel[]; showQrCode: boolean; } @@ -63,34 +56,22 @@ interface IPageState { tabValue: TabValue } -const styles = makeStyles(() => ({ - info: { - display: "flex", - justifyContent: "space-between", - }, -})) - -const Course: React.FC = (props: ICourseProps) => { +const Course: React.FC = () => { const {courseId, tab} = useParams() const [searchParams] = useSearchParams() const navigate = useNavigate() - const classes = styles() - const {enqueueSnackbar} = useSnackbar() const [courseState, setCourseState] = useState({ isFound: false, course: {}, courseHomeworks: [], - createHomework: false, mentors: [], acceptedStudents: [], newStudents: [], - isReadingMode: props.isReadingMode ?? true, studentSolutions: [], showQrCode: false }) - const [studentSolutions, setStudentSolutions] = useState([]) - const [courseFilesInfo, setCourseFilesInfo] = useState([]) + const [studentSolutions, setStudentSolutions] = useState(undefined) const [pageState, setPageState] = useState({ tabValue: "homeworks" @@ -99,11 +80,9 @@ const Course: React.FC = (props: ICourseProps) => { const { isFound, course, - createHomework, mentors, newStudents, acceptedStudents, - isReadingMode, courseHomeworks, } = courseState @@ -113,9 +92,13 @@ const Course: React.FC = (props: ICourseProps) => { const isExpert = ApiSingleton.authService.isExpert() const isMentor = isLecturer || isExpert const isCourseMentor = mentors.some(t => t.userId === userId) - const isSignedInCourse = newStudents!.some(cm => cm.userId === userId) + const { + courseFilesState, + updateCourseUnitFiles, + } = FilesUploadWaiter(+courseId!, CourseUnitType.Homework, !isCourseMentor); + const isAcceptedStudent = acceptedStudents!.some(cm => cm.userId === userId) const showStatsTab = isCourseMentor || isAcceptedStudent @@ -153,7 +136,6 @@ const Course: React.FC = (props: ICourseProps) => { isFound: true, course: course, courseHomeworks: course.homeworks!, - courseFilesInfo: courseFilesInfo, createHomework: false, mentors: course.mentors!, acceptedStudents: course.acceptedStudents!, @@ -161,19 +143,6 @@ const Course: React.FC = (props: ICourseProps) => { })) } - const getCourseFilesInfo = async () => { - // В случае, если сервис файлов недоступен, показываем пользователю сообщение - // и не блокируем остальную функциональность системы - let courseFilesInfo = [] as FileInfoDTO[] - try { - courseFilesInfo = await ApiSingleton.filesApi.filesGetFilesInfo(+courseId!) - } catch (e) { - const responseErrors = await ErrorsHandler.getErrorMessages(e as Response) - enqueueSnackbar(responseErrors[0], {variant: "warning", autoHideDuration: 4000}); - } - setCourseFilesInfo(courseFilesInfo) - } - useEffect(() => { setCurrentState() }, []) @@ -183,10 +152,6 @@ const Course: React.FC = (props: ICourseProps) => { .then(res => setStudentSolutions(res)) }, [courseId]) - useEffect(() => { - getCourseFilesInfo() - }, [courseId]) - useEffect(() => changeTab(tab || "homeworks"), [tab, courseId, isFound]) const joinCourse = async () => { @@ -197,7 +162,7 @@ const Course: React.FC = (props: ICourseProps) => { const {tabValue} = pageState const searchedHomeworkId = searchParams.get("homeworkId") - const unratedSolutionsCount = studentSolutions + const unratedSolutionsCount = (studentSolutions || []) .flatMap(x => x.homeworks) .flatMap(x => x!.tasks) .filter(t => t!.solution!.slice(-1)[0]?.state === 0) //last solution @@ -291,7 +256,7 @@ const Course: React.FC = (props: ICourseProps) => { : !isMentor ? "Вы можете записаться на курс и отправлять решения." : ""} } - @@ -346,33 +311,7 @@ const Course: React.FC = (props: ICourseProps) => { }} > {!isExpert && - -
Задания
- {isCourseMentor && - setCourseState(prevState => ({ - ...prevState, - isReadingMode: !isReadingMode - }) - )} - style={{backgroundColor: '#f1f1f1', padding: 3, marginLeft: 8}} - > - - {isReadingMode - ? - : } - - } -
- } - />} + Задания
}/>} {showStatsTab &&
Решения
@@ -387,120 +326,50 @@ const Course: React.FC = (props: ICourseProps) => { label={newStudents.length}/> }/>} - {tabValue === "homeworks" &&
- { - isReadingMode - ? - { - const homeworkIndex = courseState.courseHomeworks.findIndex(x => x.id === homework.id) - const homeworks = [...courseState.courseHomeworks] - - if (isDeleted) homeworks.splice(homeworkIndex, 1) - else homeworks[homeworkIndex] = homework - - const newCourseFiles = courseFilesInfo - .filter(x => x.homeworkId !== homework.id) - .concat(isDeleted ? [] : fileInfos) - - setCourseState(prevState => ({ - ...prevState, - courseHomeworks: homeworks - })) - setCourseFilesInfo(newCourseFiles) - }} - onTaskUpdate={task => { - const homeworks = courseState.courseHomeworks - const homework = homeworks.find(x => x.id === task.homeworkId)! - const tasks = [...homework.tasks!] - const taskIndex = tasks.findIndex(x => x!.id === task.id) - - if (task.isDeleted) tasks.splice(taskIndex, 1) - else tasks![taskIndex] = task - - homework.tasks = tasks - - setCourseState(prevState => ({ - ...prevState, - courseHomeworks: homeworks - })) - }} - /> - :
- {createHomework && ( -
- - - setCurrentState()} - onSubmit={() => setCurrentState()} - previousHomeworks={courseState.courseHomeworks} - /> - - - setCurrentState()} - isStudent={isAcceptedStudent} - isMentor={isCourseMentor} - isReadingMode={isReadingMode} - homework={courseHomeworks} - courseFilesInfo={courseFilesInfo} - /> - - -
- )} - {isLecturer && !createHomework && ( -
- - {!isReadingMode! && - - } - setCurrentState()} - isStudent={isAcceptedStudent} - isMentor={isCourseMentor} - isReadingMode={isReadingMode} - homework={courseHomeworks} - courseFilesInfo={courseFilesInfo} - /> - -
- )} - {!isCourseMentor && ( - setCurrentState()} - homework={courseHomeworks} - isStudent={isAcceptedStudent} - isMentor={isCourseMentor} - isReadingMode={isReadingMode} - courseFilesInfo={courseFilesInfo} - /> - )} -
- } -
} + {tabValue === "homeworks" && { + const homeworkIndex = courseState.courseHomeworks.findIndex(x => x.id === homework.id) + const homeworks = courseState.courseHomeworks + + if (isDeleted) homeworks.splice(homeworkIndex, 1) + else if (homeworkIndex === -1) homeworks.push(homework) + else homeworks[homeworkIndex] = homework + + setCourseState(prevState => ({ + ...prevState, + courseHomeworks: homeworks + })) + }} + onTaskUpdate={update => { + const task = update.task + const homeworks = courseState.courseHomeworks + const homework = homeworks.find(x => x.id === task.homeworkId)! + const tasks = [...homework.tasks!] + const taskIndex = tasks.findIndex(x => x!.id === task.id) + + if (update.isDeleted) tasks.splice(taskIndex, 1) + else if (taskIndex !== -1) tasks![taskIndex] = task + else tasks.push(task) + + homework.tasks = tasks + + setCourseState(prevState => ({ + ...prevState, + courseHomeworks: homeworks + })) + }} + /> + } {tabValue === "stats" && diff --git a/hwproj.front/src/components/Courses/CourseExperimental.tsx b/hwproj.front/src/components/Courses/CourseExperimental.tsx index 815d34da8..4ddd2bfdf 100644 --- a/hwproj.front/src/components/Courses/CourseExperimental.tsx +++ b/hwproj.front/src/components/Courses/CourseExperimental.tsx @@ -3,12 +3,17 @@ import { FileInfoDTO, HomeworkTaskViewModel, HomeworkViewModel, Solution, StatisticsCourseMatesModel, -} from "../../api"; +} from "@/api"; import { + AlertTitle, Button, + Fab, Grid, - Typography -} from "@material-ui/core"; + Typography, + useMediaQuery, + useTheme, + Zoom +} from "@mui/material"; import {FC, useEffect, useState} from "react"; import Timeline from '@mui/lab/Timeline'; import TimelineItem from '@mui/lab/TimelineItem'; @@ -20,24 +25,41 @@ import TimelineOppositeContent from '@mui/lab/TimelineOppositeContent'; import {Alert, Card, CardActions, Chip, Paper, Stack, Tooltip} from "@mui/material"; import {Link} from "react-router-dom"; import StudentStatsUtils from "../../services/StudentStatsUtils"; -import {getTip} from "../Common/HomeworkTags"; +import {BonusTag, DefaultTags, getTip, isBonusWork, isTestWork, TestTag} from "../Common/HomeworkTags"; import FileInfoConverter from "components/Utils/FileInfoConverter"; import CourseHomeworkExperimental from "components/Homeworks/CourseHomeworkExperimental"; import CourseTaskExperimental from "../Tasks/CourseTaskExperimental"; import {DotLottieReact} from "@lottiefiles/dotlottie-react"; +import EditIcon from "@mui/icons-material/Edit"; +import ErrorIcon from '@mui/icons-material/Error'; +import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward'; +import SwitchAccessShortcutIcon from '@mui/icons-material/SwitchAccessShortcut'; +import Lodash from "lodash"; +import {CourseUnitType} from "@/components/Files/CourseUnitType"; interface ICourseExperimentalProps { homeworks: HomeworkViewModel[] courseFilesInfo: FileInfoDTO[] studentSolutions: StatisticsCourseMatesModel[] + courseId: number isMentor: boolean isStudentAccepted: boolean userId: string selectedHomeworkId: number | undefined - onHomeworkUpdate: (update: { homework: HomeworkViewModel, fileInfos: FileInfoDTO[] } & { + onHomeworkUpdate: (update: { homework: HomeworkViewModel } & { isDeleted?: boolean }) => void - onTaskUpdate: (update: HomeworkTaskViewModel & { isDeleted?: boolean }) => void + onTaskUpdate: (update: { task: HomeworkTaskViewModel, isDeleted?: boolean }) => void, + processingFiles: { + [homeworkId: number]: { + isLoading: boolean; + }; + }; + onStartProcessing: (homeworkId: number, + courseUnitType: CourseUnitType, + previouslyExistingFilesCount: number, + waitingNewFilesCount: number, + deletingFilesIds: number[]) => void; } interface ICourseExperimentalState { @@ -48,15 +70,29 @@ interface ICourseExperimentalState { } } -const CourseExperimental: FC = (props) => { +export const CourseExperimental: FC = (props) => { const [hideDeferred, setHideDeferred] = useState(false) + const [showOnlyGroupedTest, setShowOnlyGroupedTest] = useState(undefined) + const filterAdded = hideDeferred || showOnlyGroupedTest !== undefined + + // Определяем разрешение экрана пользователя + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down('md')); + + // Состояние для кнопки "Наверх" + const [showScrollButton, setShowScrollButton] = useState(false); + + const homeworks = props.homeworks.slice().reverse().filter(x => { + if (hideDeferred) return !x.isDeferred + if (showOnlyGroupedTest !== undefined) return x.tags!.includes(TestTag) && x.tags!.includes(showOnlyGroupedTest) + return true + }) - const homeworks = props.homeworks.slice().reverse().filter(x => !hideDeferred || !x.isDeferred) const {isMentor, studentSolutions, isStudentAccepted, userId, selectedHomeworkId, courseFilesInfo} = props const [state, setState] = useState({ initialEditMode: false, - selectedItem: {id: undefined, isHomework: false}, + selectedItem: {id: undefined, isHomework: true}, }) useEffect(() => { @@ -68,6 +104,28 @@ const CourseExperimental: FC = (props) => { })) }, [hideDeferred]) + // Обработчик прокрутки страницы + useEffect(() => { + const handleScroll = () => { + // Показывать кнопку при прокрутке ниже 400px + const shouldShow = window.scrollY > 400; + if (shouldShow !== showScrollButton) { + setShowScrollButton(shouldShow); + } + }; + + window.addEventListener('scroll', handleScroll); + return () => window.removeEventListener('scroll', handleScroll); + }, [showScrollButton]); + + // Функция прокрутки вверх + const scrollToTop = () => { + window.scrollTo({ + top: 110, + behavior: 'instant' + }); + }; + const initialEditMode = state.initialEditMode const {id, isHomework} = state.selectedItem @@ -105,7 +163,7 @@ const CourseExperimental: FC = (props) => { } const getStyle = (itemIsHomework: boolean, itemId: number) => - itemIsHomework === isHomework && itemId === id ? clickedItemStyle : {} + itemIsHomework === isHomework && itemId === id ? clickedItemStyle : {borderRadius: 9} const taskSolutionsMap = new Map() @@ -117,10 +175,27 @@ const CourseExperimental: FC = (props) => { .forEach(x => taskSolutionsMap.set(x.id!, x.solution!)) } - const showWarningsForEntity = (entity: HomeworkViewModel | HomeworkTaskViewModel) => - isMentor && (entity.publicationDateNotSet || entity.hasDeadline && entity.deadlineDateNotSet) + const showWarningsForEntity = (entity: HomeworkViewModel | HomeworkTaskViewModel, isHomework: boolean) => { + if (!isMentor) return false + if (entity.publicationDateNotSet || entity.hasDeadline && entity.deadlineDateNotSet) return true + + if (!isHomework) return false + const result = validateTestGrouping(entity) + return result !== true && result.hasErrors + } - const renderTaskStatus = (task: HomeworkTaskViewModel) => { + const renderHomeworkStatus = (homework: HomeworkViewModel & { isModified?: boolean, hasErrors?: boolean }) => { + const hasErrors = homework.id! < 0 && (homework.hasErrors || homework.tasks!.some((t: HomeworkTaskViewModel & { + hasErrors?: boolean + }) => t.hasErrors)) + if (hasErrors) + return

+ if (homework.isModified) + return

+ return showWarningsForEntity(homework, true) &&
⚠️
+ } + + const renderTaskStatus = (task: HomeworkTaskViewModel & { isModified?: boolean, hasErrors?: boolean }) => { if (taskSolutionsMap.has(task.id!)) { const solutions = taskSolutionsMap.get(task.id!) const { @@ -138,7 +213,9 @@ const CourseExperimental: FC = (props) => {
) } - return showWarningsForEntity(task) ? ( + if (task.hasErrors) return + if (task.isModified) return + return showWarningsForEntity(task, false) ? ( ⚠️ @@ -157,12 +234,27 @@ const CourseExperimental: FC = (props) => { selectedItem: {id: homework.id!, isHomework: true}, }) - const getAlert = (entity: HomeworkViewModel | HomeworkTaskViewModel) => { - if (entity.publicationDateNotSet) return ( - - {"Не выставлена дата публикации"} - - ) + const validateTestGrouping = (homework: HomeworkViewModel) => { + if (!homework.tags!.includes(TestTag)) return true + + const groupingTag = homework.tags!.find(x => !DefaultTags.includes(x)) + if (groupingTag === undefined) return true + + const groupedHomeworks = homeworks.filter(x => x.tags!.includes(TestTag) && x.tags!.includes(groupingTag)) + if (groupedHomeworks.length === 1) return true + + const keys = new Set(groupedHomeworks.map(h => h.tasks!.map(t => t.maxRating).join(";"))) + return {groupingTag: groupingTag, hasErrors: keys.size !== 1} + } + + const getDatesAlert = (entity: HomeworkViewModel | HomeworkTaskViewModel, isHomework: boolean) => { + if (entity.publicationDateNotSet) { + return ( + + {"Не выставлена дата публикации"} + + ) + } if (isMentor && entity.hasDeadline && entity.deadlineDateNotSet) return ( @@ -170,9 +262,30 @@ const CourseExperimental: FC = (props) => { ) + if (entity.id! < 0) { + if (isHomework) + return Новое задание будет добавлено после нажатия на 'Добавить задание' + if ((entity as HomeworkTaskViewModel)?.homeworkId! < 0) + return setState((prevState) => ({ + ...prevState, + selectedItem: { + isHomework: true, + id: (entity as HomeworkTaskViewModel).homeworkId! + } + }))} + > + Перейти к заданию + }>Часть добавления нового задания + return Новая задача будет добавлена после нажатия на 'Добавить задачу' + } + if (entity.isDeferred) return ( = (props) => { ) } + const getGroupingAlert = (homework: HomeworkViewModel) => { + const result = validateTestGrouping(homework) + if (result === true) return null + const {hasErrors, groupingTag} = result + if (!hasErrors) return setShowOnlyGroupedTest(groupingTag)} + > + Задания + }> + Работа сгруппирована по ключу '{groupingTag}'. + - const renderSelectedItem = () => { - if (isHomework) { - const homework = homeworks.find(x => x.id === id) as HomeworkViewModel - const filesInfo = id ? FileInfoConverter.getHomeworkFilesInfo(courseFilesInfo, id) : [] - return homework && - {getAlert(homework)} - - - { - props.onHomeworkUpdate(update) - if (update.isDeleted) - setState((prevState) => ({ - ...prevState, - selectedItem: { - isHomework: true, - id: undefined - } - })) - }}/> - - - - - - + return setShowOnlyGroupedTest(groupingTag)} + > + Задания + }> + Группировка контрольных работ + Создано несколько контрольных работ, сгруппированных по ключу '{groupingTag}', + однако работы отличаются между собой по количеству задач или их максимальным баллам. +
+
+ Количество задач должно быть одинаковым, а баллы между соответствующими задачами равными. +
+ } + + const selectedItemHomework = isHomework + ? homeworks.find(x => x.id === id)! + : homeworks.find(x => x.tasks!.some(t => t.id === id))! + + const selectedItem = isHomework + ? selectedItemHomework + : selectedItemHomework?.tasks!.find(x => x.id === id) as HomeworkTaskViewModel + + const [newTaskCounter, setNewTaskCounter] = useState(-1) + + const addNewHomework = () => { + props.onHomeworkUpdate({ + homework: { + courseId: props.courseId, + title: "Новое задание", + publicationDateNotSet: false, + publicationDate: undefined, + hasDeadline: false, + id: -1, + isGroupWork: false, + deadlineDateNotSet: false, + deadlineDate: undefined, + isDeadlineStrict: false, + description: "", + tasks: [], + tags: [] + } + }) + setState((prevState) => ({ + ...prevState, + selectedItem: { + isHomework: true, + id: -1 + } + })) + } + + const addNewTask = (homework: HomeworkViewModel) => { + const id = newTaskCounter + const tags = homework.tags! + const isTest = tags.includes(TestTag) + const isBonus = tags.includes(BonusTag) + + const ratingCandidate = Lodash(homeworks + .map(h => h.tasks![0]) + .filter(x => { + if (x === undefined) return false + const xIsTest = isTestWork(x) + const xIsBonus = isBonusWork(x) + return x.id! > 0 && (isTest && xIsTest || isBonus && xIsBonus || !isTest && !isBonus && !xIsTest && !xIsBonus) + })) + .map(x => x.maxRating!) + .groupBy(x => [x]) + .entries() + .sortBy(x => x[1].length).last()?.[1][0] + + const task = { + homeworkId: homework.id, + maxRating: ratingCandidate || 10, + suggestedMaxRating: ratingCandidate, + title: `Новая задача`, + tags: homework.tags, + isDeferred: homework.isDeferred, + description: "", + id } - const homework = homeworks.find(x => x.tasks!.some(t => t.id === id)) - const task = homework?.tasks!.find(x => x.id === id) as HomeworkTaskViewModel - return task && - {getAlert(task)} - - - { - props.onTaskUpdate(update) - if (update.isDeleted) - setState((prevState) => ({ - ...prevState, - selectedItem: { - isHomework: true, - id: homework!.id - } - })) - }} - toEditHomework={() => toEditHomework(homework!)}/> - {!props.isMentor && props.isStudentAccepted && < CardActions> - - - - } - - - - ({ + ...prevState, + selectedItem: { + isHomework: false, + id: id + } + })) + setNewTaskCounter(id - 1) + } + + const renderHomework = (homework: HomeworkViewModel & { isModified?: boolean }) => { + const filesInfo = id ? FileInfoConverter.getCourseUnitFilesInfo(courseFilesInfo, CourseUnitType.Homework, id) : [] + const homeworkEditMode = homework && (homework.id! < 0 || homework.isModified === true) + return homework && + + {isMentor && getGroupingAlert(homework)} + {isMentor && getDatesAlert(homework, true)} + homeworks} + homeworkAndFilesInfo={{homework, filesInfo}} + isMentor={isMentor} + initialEditMode={initialEditMode || homeworkEditMode} + onMount={onSelectedItemMount} + onAddTask={addNewTask} + onUpdate={update => { + props.onHomeworkUpdate(update) + setState((prevState) => ({ + ...prevState, + selectedItem: { + isHomework: true, + id: update.isDeleted ? undefined : update.homework.id! + } + })) + }} + isProcessing={props.processingFiles[homework.id!]?.isLoading || false} + onStartProcessing={props.onStartProcessing} /> - - + + } - return - - { + const taskEditMode = task && (task.id! < 0 || task.isModified === true) + return task && + {isMentor && getDatesAlert(task, false)} + { + props.onTaskUpdate(update) + if (update.isDeleted) + setState((prevState) => ({ + ...prevState, + selectedItem: { + isHomework: true, + id: homework!.id + } + })) + }} + toEditHomework={() => toEditHomework(homework!)} getAllHomeworks={() => homeworks}/> + {!props.isMentor && props.isStudentAccepted && < CardActions> + + + + } + + } + + const renderGif = () => + + + const renderLecturerWelcomeScreen = () => + + + Спасибо за ещё один курс + Самое время добавить новое задание! + + + + return + + = (props) => { borderRadius: 10 } }}> - {homeworks.map(x => { - return
+ {props.isMentor && filterAdded && + + {hideDeferred + ? "только опубликованные задания" + : showOnlyGroupedTest + ? `контрольные работы '${showOnlyGroupedTest}'` + : ""} + + } + {props.isMentor && !filterAdded && (homeworks[0]?.id || 1) > 0 && } + {isMentor && homeworks.length === 0 && renderLecturerWelcomeScreen()} + {homeworks.map((x: HomeworkViewModel & { isModified?: boolean, hasErrors?: boolean }) => { + return
= (props) => { data: x, isHomework: true, id: x.id, - homeworkFilesInfo: FileInfoConverter.getHomeworkFilesInfo(courseFilesInfo, x.id!) + homeworkFilesInfo: FileInfoConverter.getCourseUnitFilesInfo(courseFilesInfo, CourseUnitType.Homework, x.id!) } })) }}> - {showWarningsForEntity(x) &&
⚠️
} + color={x.isDeferred + ? "textSecondary" + : x.tags!.includes(TestTag) ? "primary" : "textPrimary"}> + {isMentor && renderHomeworkStatus(x)} {x.title}{getTip(x)}
{x.isDeferred && !x.publicationDateNotSet && @@ -358,15 +618,47 @@ const CourseExperimental: FC = (props) => { )} + {x.id! < 0 && + }
; })} - - - {renderSelectedItem()} + + {isHomework + ? renderHomework(selectedItem as HomeworkViewModel) + : renderTask(selectedItem as HomeworkTaskViewModel, selectedItemHomework!)} + + {renderGif()} + + + {renderGif()} + + + {/* Кнопка "Наверх" для мобильных устройств */} + + + + + } - -export default CourseExperimental diff --git a/hwproj.front/src/components/Courses/CourseFilter.tsx b/hwproj.front/src/components/Courses/CourseFilter.tsx index b4761bc66..04d2fea2c 100644 --- a/hwproj.front/src/components/Courses/CourseFilter.tsx +++ b/hwproj.front/src/components/Courses/CourseFilter.tsx @@ -1,11 +1,11 @@ import React, {FC, useEffect, useState} from 'react'; -import {HomeworkViewModel, AccountDataDto} from '../../api'; +import {HomeworkViewModel, AccountDataDto, MentorToAssignedStudentsDTO} from '../../api'; import Grid from "@material-ui/core/Grid"; -import {Autocomplete} from "@mui/material"; +import {Autocomplete, Chip, Stack, Typography} from "@mui/material"; import TextField from "@material-ui/core/TextField"; import ApiSingleton from "../../api/ApiSingleton"; import ErrorsHandler from "../Utils/ErrorsHandler"; -import { DotLottieReact } from '@lottiefiles/dotlottie-react'; +import {DotLottieReact} from '@lottiefiles/dotlottie-react'; import Button from "@material-ui/core/Button"; interface ICourseFilterProps { @@ -22,6 +22,8 @@ interface ICourseFilterState { courseStudents: AccountDataDto[]; selectedHomeworks: HomeworkViewModel[]; selectedStudents: AccountDataDto[]; + mentors: AccountDataDto[]; + assignedStudents: MentorToAssignedStudentsDTO[] } // Если преподаватель не выбрал ни одного студента, по умолчанию регистрируем всех. Аналогично с выбором домашних работ @@ -30,7 +32,9 @@ const CourseFilter: FC = (props) => { courseHomeworks: [], courseStudents: [], selectedHomeworks: [], - selectedStudents: [] + selectedStudents: [], + assignedStudents: [], + mentors: [] }); // Состояние для отображения элемента загрузки @@ -39,16 +43,15 @@ const CourseFilter: FC = (props) => { // Состояние для отображения поля выбора студентов const [isStudentsSelectionHidden, setIsStudentsSelectionHidden] = useState(props.isStudentsSelectionHidden); - // Если у преподавателя в workspace все студенты, отображаем "Все" в компоненте, значений при этом не выбрано. - // Функция, необходимые для корректного отображения выбранных элементов. - function getItemsView(selected: T[], all: T[]): T[] { - return selected.length === all.length ? [] : selected; - } - useEffect(() => { const fetchCourseDataForMentor = async () => { try { - const courseViewModel = await ApiSingleton.coursesApi.coursesGetAllCourseData(props.courseId); + const { + course, + assignedStudents + } = await ApiSingleton.coursesApi.coursesGetAllCourseData(props.courseId); + if (course === undefined || assignedStudents === undefined) return + const mentorWorkspace = await ApiSingleton.coursesApi.coursesGetMentorWorkspace(props.courseId, props.mentorId); @@ -56,18 +59,20 @@ const CourseFilter: FC = (props) => { props.onSelectedHomeworksChange(mentorWorkspace.homeworks ?? []) // Для корректного отображения "Все" при инцициализации (получении данных с бэкенда) - const allCourseStudentsCount = (courseViewModel.acceptedStudents?.length ?? 0) + (courseViewModel.newStudents?.length ?? 0); + const allCourseStudentsCount = (course.acceptedStudents?.length ?? 0) + (course.newStudents?.length ?? 0); const initSelectedStudentsView = mentorWorkspace.students?.length === allCourseStudentsCount ? [] : (mentorWorkspace.students) ?? []; - const initSelectedHomeworksView = mentorWorkspace.homeworks?.length === courseViewModel.homeworks?.length ? + const initSelectedHomeworksView = mentorWorkspace.homeworks?.length === course.homeworks?.length ? [] : (mentorWorkspace.homeworks ?? []); setState(prevState => ({ ...prevState, - courseHomeworks: courseViewModel.homeworks ?? [], - courseStudents: courseViewModel.acceptedStudents ?? [], + courseHomeworks: course.homeworks ?? [], + courseStudents: course.acceptedStudents ?? [], selectedStudents: initSelectedStudentsView, selectedHomeworks: initSelectedHomeworksView, + mentors: course.mentors!, + assignedStudents: assignedStudents.filter(x => x.mentorId !== props.mentorId) })) setIsLoading(false); @@ -94,6 +99,20 @@ const CourseFilter: FC = (props) => { props.onSelectedHomeworksChange(state.selectedHomeworks) }, [state.selectedHomeworks]); + //TODO: memoize? + const getAssignedMentors = (studentId: string) => + state.assignedStudents + .filter(x => x.selectedStudentsIds!.includes(studentId)) + .map(x => state.mentors.find(m => m.userId === x.mentorId)) + .filter(x => x !== undefined) + .map(x => x.name + ' ' + x.surname) + + const studentsWithMultipleReviewers = new Set( + state.selectedStudents + .map(x => x.userId!) + .filter(x => getAssignedMentors(x).length > 0) + ) + return (
{isLoading ? ( @@ -121,11 +140,11 @@ const CourseFilter: FC = (props) => { )} - noOptionsText={'На курсе больше нет работ'} + noOptionsText={'Больше нет заданий для выбора'} value={state.selectedHomeworks} onChange={(_, values) => { setState((prevState) => ({ @@ -146,30 +165,48 @@ const CourseFilter: FC = (props) => { ) : ( - option.name + ' ' + option.surname} - getOptionKey={(option: AccountDataDto) => option.userId ?? ""} - filterSelectedOptions - isOptionEqualToValue={(option, value) => option.userId === value.userId} - renderInput={(params) => ( - )} - noOptionsText={'На курсе больше нет студентов'} - value={state.selectedStudents} - onChange={(_, values) => { - setState((prevState) => ({ - ...prevState, - selectedStudents: values - })); - }} - /> + + { + const assignedMentors = getAssignedMentors(option.userId!) + const suffix = assignedMentors.length > 0 ? " — преподаватель " + assignedMentors[0] + "" : "" + return option.surname + ' ' + option.name + suffix; + }} + getOptionKey={(option: AccountDataDto) => option.userId ?? ""} + filterSelectedOptions + isOptionEqualToValue={(option, value) => option.userId === value.userId} + renderInput={(params) => ( + )} + renderTags={(value, getTagProps) => + value.map((option, index) => + ) + } + noOptionsText={'Больше нет студентов для выбора'} + value={state.selectedStudents} + onChange={(_, values) => { + setState((prevState) => ({ + ...prevState, + selectedStudents: values + })); + }} + /> + {studentsWithMultipleReviewers.size > 0 && + + Синим выделены студенты, закрепленные за несколькими преподавателями + } + diff --git a/hwproj.front/src/components/Courses/Courses.tsx b/hwproj.front/src/components/Courses/Courses.tsx index 0e009dda3..51413db05 100644 --- a/hwproj.front/src/components/Courses/Courses.tsx +++ b/hwproj.front/src/components/Courses/Courses.tsx @@ -38,18 +38,6 @@ export default class Courses extends React.Component { const {isLoaded, allCourses, myCourses, tabValue} = this.state; const {navigate} = this.props.navigate; - if (!isLoaded) { - return ( -
- -
- ); - } - const activeCourses = myCourses.filter(course => !course.isCompleted) const completedCourses = myCourses.filter(course => course.isCompleted) const isExpert = this.props.isExpert @@ -76,11 +64,14 @@ export default class Courses extends React.Component { {completedCourses.length > 0 && } {tabValue === activeCoursesTab && - } + } {tabValue === allCoursesTab && !isExpert - && } + && + } {tabValue === completedCoursesTab && - } + }
); } diff --git a/hwproj.front/src/components/Courses/CoursesList.tsx b/hwproj.front/src/components/Courses/CoursesList.tsx index 56701d49e..4bf3917d5 100644 --- a/hwproj.front/src/components/Courses/CoursesList.tsx +++ b/hwproj.front/src/components/Courses/CoursesList.tsx @@ -1,37 +1,53 @@ import * as React from "react"; -import {CoursePreviewView} from "../../api/"; +import {CoursePreviewView} from "@/api"; import {NavLink} from "react-router-dom"; import MentorsList from "../Common/MentorsList"; -import {Box, Divider, Grid, ListItem, Typography} from "@mui/material"; +import {Box, Chip, Divider, Grid, ListItem, Skeleton, Stack, Typography} from "@mui/material"; import NameBuilder from "../Utils/NameBuilder"; interface ICoursesProps { navigate: any - courses: CoursePreviewView[]; + courses: CoursePreviewView[] | undefined; isExpert: boolean } export class CoursesList extends React.Component { public render() { const {courses, isExpert} = this.props; + const ghostCoursesRand = [45, 12, 23, 3, 67, 50, 19] return ( - {courses.map((course, i) => ( + {courses === undefined && ghostCoursesRand.map((rand, i) => { + return + + + + {i < ghostCoursesRand.length - 1 ? + : null} + ; + })} + {courses && courses.map((course, i) => ( - - - {NameBuilder.getCourseFullName(course.name!, course.groupName)} - - + + + + {NameBuilder.getCourseFullName(course.name!, course.groupName)} + + + {course.isCompleted && + } + {i < courses.length - 1 ? : null} diff --git a/hwproj.front/src/components/Courses/CreateCourse.tsx b/hwproj.front/src/components/Courses/CreateCourse.tsx index 64bf03bbf..0a481c015 100644 --- a/hwproj.front/src/components/Courses/CreateCourse.tsx +++ b/hwproj.front/src/components/Courses/CreateCourse.tsx @@ -5,7 +5,6 @@ import { StepLabel, StepButton, Typography, - } from "@material-ui/core"; import ApiSingleton from "../../api/ApiSingleton"; import {CoursePreviewView} from "api"; @@ -54,8 +53,7 @@ export const CreateCourse: FC = () => { programNames: [], programName: "", groupNames: [], - groupName: "", - + selectedGroups: [], fetchingGroups: false, courseIsLoading: false, }) @@ -132,7 +130,7 @@ export const CreateCourse: FC = () => { e.preventDefault() const courseViewModel = { name: state.courseName, - groupName: state.groupName, + groupNames: state.selectedGroups, isOpen: true, baseCourseId: selectedBaseCourse?.id, fetchStudents: state.isGroupFromList ? state.fetchStudents : false, @@ -140,24 +138,23 @@ export const CreateCourse: FC = () => { try { setCourseIsLoading(true) const courseId = await ApiSingleton.coursesApi.coursesCreateCourse(courseViewModel) - navigate(`/courses/${courseId}/editHomeWorks`) + navigate(`/courses/${courseId}`) } catch (e) { console.error("Ошибка при создании курса:", e) const responseErrors = await ErrorsHandler.getErrorMessages(e as Response) enqueueSnackbar(responseErrors[0], {variant: "error"}) + } finally { + setCourseIsLoading(false) } } - // Load base courses and program names on mount useEffect(() => { const loadData = async () => { try { - // Load base courses const userCourses = await ApiSingleton.coursesApi.coursesGetAllUserCourses(); if (!userCourses.length) skipCurrentStep(); setBaseCourses(userCourses); - // Load program names const programResponse = await ApiSingleton.coursesApi.coursesGetProgramNames(); const programNames = programResponse .map(model => model.programName) @@ -197,7 +194,6 @@ export const CreateCourse: FC = () => { } }; - // Load groups when program name changes useEffect(() => { if (state.programName) { fetchGroups(state.programName); @@ -255,4 +251,4 @@ export const CreateCourse: FC = () => { />
) -} +} \ No newline at end of file diff --git a/hwproj.front/src/components/Courses/ICreateCourseState.tsx b/hwproj.front/src/components/Courses/ICreateCourseState.tsx index 4b70df5e4..add096860 100644 --- a/hwproj.front/src/components/Courses/ICreateCourseState.tsx +++ b/hwproj.front/src/components/Courses/ICreateCourseState.tsx @@ -14,7 +14,6 @@ export const stepLabels = [ export const stepIsOptional = (step: CreateCourseStep) => step === CreateCourseStep.SelectBaseCourseStep -//TODO: refactor export interface ICreateCourseState { activeStep: CreateCourseStep; completedSteps: Set; @@ -28,9 +27,8 @@ export interface ICreateCourseState { programName: string; groupNames: string[]; - groupName: string; + selectedGroups: string[]; isGroupFromList: boolean; - fetchStudents: boolean; fetchingGroups: boolean; @@ -40,4 +38,4 @@ export interface ICreateCourseState { export interface IStepComponentProps { state: ICreateCourseState; setState: Dispatch>; -} +} \ No newline at end of file diff --git a/hwproj.front/src/components/Courses/MentorWorkspaceModal.tsx b/hwproj.front/src/components/Courses/MentorWorkspaceModal.tsx index 8f455dca1..772ebb29c 100644 --- a/hwproj.front/src/components/Courses/MentorWorkspaceModal.tsx +++ b/hwproj.front/src/components/Courses/MentorWorkspaceModal.tsx @@ -74,73 +74,57 @@ const MentorWorkspaceModal: FC = (props) => { -
- - {state.errors.length > 0 && ( -

{state.errors}

- )} -
- {!isWorkspaceLoading && - - Здесь Вы можете изменить область работы преподавателя - } - + + {state.errors.length > 0 && ( +

{state.errors}

+ )} +
+ {!isWorkspaceLoading && + + Здесь Вы можете изменить область работы преподавателя + } + + setState(prevState => ({ + ...prevState, + selectedHomeworks: homeworks + })) + } + onSelectedStudentsChange={(students) => + setState(prevState => ({ + ...prevState, + selectedStudents: students + })) + } + onWorkspaceInitialize={(success, errors) => { + if (!success) { setState(prevState => ({ ...prevState, - selectedHomeworks: homeworks + errors: errors ?? ['Сервис недоступен'] })) } - onSelectedStudentsChange={(students) => - setState(prevState => ({ - ...prevState, - selectedStudents: students - })) - } - onWorkspaceInitialize={(success, errors) => { - if (!success) { - setState(prevState => ({ - ...prevState, - errors: errors ?? ['Сервис недоступен'] - })) - } - setIsWorkspaceLoading(false) - }} - /> - {!isWorkspaceLoading && - - - - - - - - } -
+ setIsWorkspaceLoading(false) + }} + />
- - + {!isWorkspaceLoading && + + + } = (props) => { if (studentsLength === 0) { return ( -
- Нет новых заявок в курс. -
+ + + На данный момент все заявки приняты! + + Уведомления о новых заявках на Ваших курсах так же будут отображены на главной странице сервиса + ) } - return + return {props.students.map((cm, i) => ( diff --git a/hwproj.front/src/components/Courses/Statistics/StudentStatsChart.tsx b/hwproj.front/src/components/Courses/Statistics/StudentStatsChart.tsx index d193467c9..10b7720ea 100644 --- a/hwproj.front/src/components/Courses/Statistics/StudentStatsChart.tsx +++ b/hwproj.front/src/components/Courses/Statistics/StudentStatsChart.tsx @@ -6,7 +6,7 @@ import { HomeworkViewModel, StatisticsCourseHomeworksModel, StatisticsCourseMatesModel, StatisticsCourseMeasureSolutionModel -} from "../../../api/"; +} from "@/api"; import ApiSingleton from "../../../api/ApiSingleton"; import HelpPopoverChartInfo from './HelpPopoverChartInfo'; import StudentCheckboxList from "./StudentCheckboxList"; @@ -14,6 +14,8 @@ import StudentProgressChart from "./StudentProgressChart"; import StudentPunctualityChart from './StudentPunctualityChart'; import NameBuilder from "../../Utils/NameBuilder"; import {DotLottieReact} from "@lottiefiles/dotlottie-react"; +import { StudentsRadarChart } from "./StudentsRadarChart"; +import {appBarStateManager} from "@/components/AppBar"; interface IStudentStatsChartState { isFound: boolean; @@ -41,11 +43,11 @@ const StudentStatsChart: React.FC = () => { averageStudent: [] }) const [sectorSizes, setSectorSizes] = useState([]); - const tasksSolutionLength = (hw : StatisticsCourseHomeworksModel[], tasksWithDeadline : HomeworkTaskViewModel[]) => + const tasksSolutionLength = (hw: StatisticsCourseHomeworksModel[], tasksWithDeadline: HomeworkTaskViewModel[]) => hw.flatMap(h => h.tasks! .filter(task => tasksWithDeadline.find(t => t.id === task.id)) .map(t => t.solution!.length)) - const handleStudentSelection = (studentIds : string[]) => { + const handleStudentSelection = (studentIds: string[]) => { const newSectorSizes = sectorSizes.map((_, i) => { const taskSectorSizes = studentIds.map(id => { const studentHomeworks = state.solutions @@ -86,6 +88,8 @@ const StudentStatsChart: React.FC = () => { useEffect(() => { setCurrentState() + appBarStateManager.setContextAction({actionName: "К курсу", link: `/courses/${courseId}/stats`}) + return () => appBarStateManager.reset() }, []) useEffect(() => { @@ -99,19 +103,6 @@ const StudentStatsChart: React.FC = () => { return student.name + ' ' + student.surname; } - const renderGoBackToCoursesStatsLink = () => { - return ( - - - Назад к курсу - - - ) - } - const tasks = state.homeworks.flatMap(h => h.tasks ?? []) const tasksAmount = tasks.length const tasksWithDeadlineAmount = state.tasksWithDeadline.length @@ -138,9 +129,6 @@ const StudentStatsChart: React.FC = () => { бета - - {isLoggedIn && renderGoBackToCoursesStatsLink()} - {state.isSelectionMode && @@ -155,6 +143,15 @@ const StudentStatsChart: React.FC = () => { } + {selectedStudents.length > 0 && + + } diff --git a/hwproj.front/src/components/Courses/Statistics/StudentsRadarChart.tsx b/hwproj.front/src/components/Courses/Statistics/StudentsRadarChart.tsx new file mode 100644 index 000000000..566bad926 --- /dev/null +++ b/hwproj.front/src/components/Courses/Statistics/StudentsRadarChart.tsx @@ -0,0 +1,55 @@ +import {HomeworkViewModel, StatisticsCourseMatesModel, StatisticsCourseMeasureSolutionModel} from "@/api"; +import {Unstable_RadarChart as RadarChart} from '@mui/x-charts/RadarChart'; +import {FC} from "react"; +import StudentStatsUtils from "@/services/StudentStatsUtils"; + +export const StudentsRadarChart: FC<{ + selectedStudents: string[], + homeworks: HomeworkViewModel[], + solutions: StatisticsCourseMatesModel[], + averageStudent: StatisticsCourseMeasureSolutionModel[] +}> = (props) => { + const homeworks = props.homeworks + .filter(h => h.tasks!.length > 0) + + const metrics = homeworks + .map(x => ({ + name: x.title! + `[id${x.id!}]`, + id: x.id!, + max: x.tasks! + .map(x => x.maxRating!) + .reduce((a, b) => a + b) + })) + + const series = props.solutions + .filter(x => props.selectedStudents.includes(x.id!)) + .map(x => ({ + label: x.surname + " " + x.name, + fillArea: true, + data: metrics + .map(m => x.homeworks!.find(t => t.id === m.id)) + .map(x => x!.tasks! + .flatMap(y => StudentStatsUtils.calculateLastRatedSolution(y.solution!)?.rating || 0) + .reduce((a, b) => a + b)) + })) + + const averageStudent = { + label: "Средний студент", + fillArea: true, + data: homeworks + .map(h => h.tasks! + .map(t => props.averageStudent.find(y => y.taskId === t.id)?.rating || 0) + .reduce((a, b) => a + b)) + } + + series.push(averageStudent) + + return 10 ? (homeworks.length - 10) * 10 : 0)} + series={series} + radar={{ + metrics, + labelFormatter: (name: string, _) => name.replace(/\[id\d+]/g, "") + }} + /> +} diff --git a/hwproj.front/src/components/Courses/StudentStats.tsx b/hwproj.front/src/components/Courses/StudentStats.tsx index f22b80867..8a31c9ae3 100644 --- a/hwproj.front/src/components/Courses/StudentStats.tsx +++ b/hwproj.front/src/components/Courses/StudentStats.tsx @@ -1,21 +1,24 @@ -import React, {useEffect, useState} from "react"; -import {CourseViewModel, HomeworkViewModel, StatisticsCourseMatesModel} from "../../api/"; +import React, {useEffect, useState, useRef} from "react"; +import {CourseViewModel, HomeworkViewModel, StatisticsCourseMatesModel} from "@/api"; import {useNavigate, useParams} from 'react-router-dom'; -import {Table, TableBody, TableCell, TableContainer, TableHead, TableRow} from "@material-ui/core"; +import {LinearProgress, Table, TableBody, TableCell, TableContainer, TableHead, TableRow} from "@material-ui/core"; import StudentStatsCell from "../Tasks/StudentStatsCell"; -import {Alert, Button, Chip, Typography} from "@mui/material"; +import {Alert, Button, Chip, IconButton, Typography} from "@mui/material"; import {grey} from "@material-ui/core/colors"; import StudentStatsUtils from "../../services/StudentStatsUtils"; import ShowChartIcon from "@mui/icons-material/ShowChart"; import {BonusTag, DefaultTags, TestTag} from "../Common/HomeworkTags"; import Lodash from "lodash" +import ApiSingleton from "@/api/ApiSingleton"; +import FullscreenIcon from '@mui/icons-material/Fullscreen'; +import FullscreenExitIcon from '@mui/icons-material/FullscreenExit'; interface IStudentStatsProps { course: CourseViewModel; homeworks: HomeworkViewModel[]; isMentor: boolean; userId: string; - solutions: StatisticsCourseMatesModel[]; + solutions: StatisticsCourseMatesModel[] | undefined; } interface IStudentStatsState { @@ -34,10 +37,36 @@ const StudentStats: React.FC = (props) => { navigate(`/statistics/${courseId}/charts`) } + const [isFullscreen, setIsFullscreen] = useState(false) + + const tableRef = useRef(null) + + const toggleFullscreen = () => { + const target = tableRef.current + if (!target) return + if (!document.fullscreenElement) { + if (target.requestFullscreen) { + target.requestFullscreen() + } + } else { + if (document.exitFullscreen) { + document.exitFullscreen() + } + } + } + + useEffect(() => { + const onFsChange = () => setIsFullscreen(!!document.fullscreenElement) + document.addEventListener('fullscreenchange', onFsChange) + return () => document.removeEventListener('fullscreenchange', onFsChange) + }, []) + const {searched} = state + const isMentor = ApiSingleton.authService.isMentor() useEffect(() => { const keyDownHandler = (event: KeyboardEvent) => { + if (document.fullscreenElement) return if (event.ctrlKey || event.altKey) return if (searched && event.key === "Escape") { setSearched({searched: ""}); @@ -55,7 +84,7 @@ const StudentStats: React.FC = (props) => { const homeworks = props.homeworks.filter(h => h.tasks && h.tasks.length > 0) const solutions = searched - ? props.solutions.filter(cm => (cm.surname + " " + cm.name).toLowerCase().includes(searched.toLowerCase())) + ? props.solutions?.filter(cm => (cm.surname + " " + cm.name).toLowerCase().includes(searched.toLowerCase())) : props.solutions const borderStyle = `1px solid ${greyBorder}` @@ -97,24 +126,53 @@ const StudentStats: React.FC = (props) => { const hasHomeworks = homeworksMaxSum > 0 const hasTests = testsMaxSum > 0 + const showBestSolutions = isMentor && (hasHomeworks || hasTests) + + const bestTaskSolutions = new Map() + if (props.solutions && isMentor) { + Lodash(homeworks) + .flatMap(h => h.tasks!) + .map(t => props.solutions! + .map(s => s.homeworks! + .flatMap(h1 => h1.tasks!) + .find(t1 => t1.id === t.id)?.solution || []) + .map(s => StudentStatsUtils.calculateLastRatedSolution(s)) + .filter(x => x != undefined && x.rating! > 0)) + .filter(x => x.length > 0) + .map(x => Lodash(x).orderBy([ + (x) => x.rating, + (x) => new Date(x.publicationDate!).getTime() + ], ["desc", "asc"]).value()[0] + ) + .forEach(x => bestTaskSolutions.set(x.taskId!, x.studentId!)) + } return (
+ {props.solutions === undefined && } + {props.solutions && props.solutions.length === 0 && + На курс пока ещё никто не записался + } {searched && Поиск: {searched.replaceAll(" ", "·")} } - + - + + {isFullscreen + ? + : } + {(hasHomeworks || hasTests) && = (props) => { - {solutions.length > 0 && + {solutions && solutions.length > 0 && - - - - - - - - - + Зарегистрировать + + + + ) diff --git a/hwproj.front/src/components/Files/CourseUnitType.ts b/hwproj.front/src/components/Files/CourseUnitType.ts new file mode 100644 index 000000000..cee551ca5 --- /dev/null +++ b/hwproj.front/src/components/Files/CourseUnitType.ts @@ -0,0 +1,5 @@ +export enum CourseUnitType { + Homework = "Homework", + Task = "Task", + Solution = "Solution" +} \ No newline at end of file diff --git a/hwproj.front/src/components/Files/FilePreview.tsx b/hwproj.front/src/components/Files/FilePreview.tsx index a9abc7ed1..b1d9f7725 100644 --- a/hwproj.front/src/components/Files/FilePreview.tsx +++ b/hwproj.front/src/components/Files/FilePreview.tsx @@ -1,21 +1,27 @@ import React, {useEffect, useState} from 'react'; -import {Box, Typography, IconButton} from '@mui/material'; +import {Box, Typography, IconButton, useTheme, CircularProgress} from '@mui/material'; import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; import ImageIcon from '@mui/icons-material/Image'; import PictureAsPdfIcon from '@mui/icons-material/PictureAsPdf'; import DescriptionIcon from '@mui/icons-material/Description'; import CloseIcon from '@mui/icons-material/Close'; +import CheckCircleIcon from '@mui/icons-material/CheckCircle'; +import ErrorIcon from '@mui/icons-material/Error'; import {IFileInfo} from './IFileInfo'; -import LightTooltip from 'components/Common/LightTooltip'; +import {FileStatus} from "./FileStatus"; +import LightTooltip from '../Common/LightTooltip'; interface FilePreviewProps { fileInfo: IFileInfo; onClick?: (f: IFileInfo) => void; onRemove?: (f: IFileInfo) => void; + showOkStatus?: boolean; } const FilePreview: React.FC = (props) => { + const theme = useTheme(); const [previewUrl, setPreviewUrl] = useState(null); + const hasRemoveButton = !!props.onRemove; useEffect(() => { if (props.fileInfo.file && props.fileInfo.type?.startsWith('image/')) { @@ -27,16 +33,23 @@ const FilePreview: React.FC = (props) => { }, [props.fileInfo.file]); const getFileIcon = () => { - const iconStyle = {fontSize: 28}; - if (props.fileInfo.type?.startsWith('image/') - || props.fileInfo.name.endsWith('png') || props.fileInfo.name.endsWith('jpg') - || props.fileInfo.name.endsWith('jpeg')) + const iconStyle = {fontSize: 24}; + if (props.fileInfo.type?.startsWith('image/') || + props.fileInfo.name.endsWith('png') || + props.fileInfo.name.endsWith('jpg') || + props.fileInfo.name.endsWith('jpeg')) { return ; - if (props.fileInfo.type === 'application/pdf' || props.fileInfo.name.endsWith('pdf')) + } + if (props.fileInfo.type === 'application/pdf' || + props.fileInfo.name.endsWith('pdf')) { return ; - if (props.fileInfo.type?.startsWith('text/') || props.fileInfo.name.endsWith('txt') - || props.fileInfo.name.endsWith('doc') || props.fileInfo.name.endsWith('docx')) + } + if (props.fileInfo.type?.startsWith('text/') || + props.fileInfo.name.endsWith('txt') || + props.fileInfo.name.endsWith('doc') || + props.fileInfo.name.endsWith('docx')) { return ; + } return ; }; @@ -46,108 +59,207 @@ const FilePreview: React.FC = (props) => { if (sizeInMB >= 1) { return `${sizeInMB.toFixed(1)} MB`; - } else { - return `${sizeInKB.toFixed(1)} KB`; } + return `${sizeInKB.toFixed(1)} KB`; } - - const hasRemoveButton = !!props.onRemove; + + const getStatusInfo = (status: FileStatus) => { + switch (status) { + case FileStatus.Uploading: + return { + text: "Загружаем", + tooltipText: "", + icon: , + color: { + bg: theme.palette.grey[200], + text: theme.palette.info.main + } + }; + case FileStatus.Deleting: + return { + text: "Удаляем", + tooltipText: "", + icon: , + color: { + bg: theme.palette.grey[200], + text: theme.palette.info.main + } + }; + case FileStatus.UploadingError: + return { + text: "Ошибка загрузки", + // tooltipText: "" "Нажмите, чтобы повторить загрузку", + icon: , + color: { + bg: theme.palette.grey[200], + text: theme.palette.error.dark + } + }; + case FileStatus.DeletingError: + return { + text: "Ошибка удаления", + // tooltipText: "Нажмите, чтобы повторить удаление", + icon: , + color: { + bg: theme.palette.grey[200], + text: theme.palette.error.dark + } + }; + case FileStatus.ReadyToUse: + return { + tooltipText: "", + icon: props.showOkStatus ? + : <>, + color: { + bg: theme.palette.grey[200], + text: theme.palette.success.dark + } + }; + default: + return { + text: "", + tooltipText: "", + icon: <>, + color: { + bg: theme.palette.grey[200], + text: theme.palette.text.secondary + } + }; + } + } + + const statusInfo = getStatusInfo(props.fileInfo.status); return ( - {/*Превью изображения*/} - {previewUrl ? ( - Preview - ) : ( - props.onClick?.(props.fileInfo)} - sx={{ - width: hasRemoveButton ? 32 : 28, - height: hasRemoveButton ? 32 : 28, - flexShrink: 0, + {/* Обертка для превью/иконки */} + + {previewUrl ? ( + Preview + ) : ( + - {getFileIcon()} - - )} + {getFileIcon()} + + )} + - {/*Текстовая информация*/} + {/* Текстовая информация */} props.onClick?.(props.fileInfo)} sx={{ - flex: '1 1 auto', + flex: 1, minWidth: 0, - maxWidth: 200, - paddingRight: hasRemoveButton ? 3 : 1, - marginRight: hasRemoveButton ? 0 : 0, cursor: props.onClick ? 'pointer' : 'default', }}> - + + {props.fileInfo.name} + + + - {props.fileInfo.name} + {getFileSize(props.fileInfo.sizeInBytes)} - - - {getFileSize(props.fileInfo.sizeInBytes)} - + + + {statusInfo.icon} + + + {statusInfo.text} + + + + - {hasRemoveButton && props.onRemove!(props.fileInfo)} - sx={{ - position: 'absolute', - right: 4, - top: '50%', - transform: 'translateY(-50%)', - padding: 0.5, - '& svg': { - fontSize: hasRemoveButton ? '1rem' : '0.8rem' - } - }} - > - - } + {hasRemoveButton && ( + props.onRemove!(props.fileInfo)} + sx={{ + flexShrink: 0, + color: theme.palette.text.secondary + }} + > + + + )} ); }; -export default FilePreview \ No newline at end of file +export default FilePreview; \ No newline at end of file diff --git a/hwproj.front/src/components/Files/FileStatus.ts b/hwproj.front/src/components/Files/FileStatus.ts new file mode 100644 index 000000000..6a99cc914 --- /dev/null +++ b/hwproj.front/src/components/Files/FileStatus.ts @@ -0,0 +1,8 @@ +export enum FileStatus { + Local = "Local", + Uploading = "Uploading", + UploadingError = "UploadingError", + ReadyToUse = "ReadyToUse", + Deleting = "Deleting", + DeletingError = "DeletingError" +} \ No newline at end of file diff --git a/hwproj.front/src/components/Files/FilesHandler.ts b/hwproj.front/src/components/Files/FilesHandler.ts new file mode 100644 index 000000000..49791b747 --- /dev/null +++ b/hwproj.front/src/components/Files/FilesHandler.ts @@ -0,0 +1,85 @@ +import {IFileInfo} from "@/components/Files/IFileInfo"; +import {CourseUnitType} from "@/components/Files/CourseUnitType"; +import ApiSingleton from "@/api/ApiSingleton"; +import ErrorsHandler from "@/components/Utils/ErrorsHandler"; +import {useState} from "react"; +import {enqueueSnackbar} from "notistack"; + +export interface IEditFilesState { + initialFilesInfo: IFileInfo[] + selectedFilesInfo: IFileInfo[] + isLoadingInfo: boolean +} + +export const FilesHandler = (selectedFilesInfo: IFileInfo[]) => { + const [filesState, setFilesState] = useState({ + initialFilesInfo: selectedFilesInfo.filter(x => x.id !== undefined), + selectedFilesInfo: selectedFilesInfo, + isLoadingInfo: false + }); + + const handleFilesChange = async (courseId: number, + courseUnitType: CourseUnitType, + courseUnitId: number, + onStartProcessing: (courseUnitId: number, + courseUnitType: CourseUnitType, + previouslyExistingFilesCount: number, + waitingNewFilesCount: number, + deletingFilesIds: number[]) => void, + onComplete: () => void, + ) => { + // Если какие-то файлы из ранее добавленных больше не выбраны, их потребуется удалить + const deletingFileIds = filesState.initialFilesInfo.filter(initialFile => + initialFile.id && !filesState.selectedFilesInfo.some(sf => sf.id === initialFile.id)) + .map(fileInfo => fileInfo.id!) + + // Если какие-то файлы из выбранных сейчас не были добавлены раньше, они новые + const newFiles = filesState.selectedFilesInfo.filter(selectedFile => + selectedFile.file && selectedFile.id == undefined).map(fileInfo => fileInfo.file!) + + // Если требуется, отправляем запрос на обработку файлов + if (deletingFileIds.length + newFiles.length > 0) { + try { + await ApiSingleton.customFilesApi.processFiles({ + courseId: courseId!, + courseUnitType: courseUnitType, + courseUnitId: courseUnitId!, + deletingFileIds, + newFiles, + }); + } catch (e) { + const errors = await ErrorsHandler.getErrorMessages(e as Response); + enqueueSnackbar(errors[0], { + variant: "warning", + autoHideDuration: 2000 + }); + } + } + if (deletingFileIds.length === 0 && newFiles.length === 0) { + onComplete(); + } else { + try { + onComplete(); + onStartProcessing( + courseUnitId!, + courseUnitType, + filesState.initialFilesInfo.length, + newFiles.length, + deletingFileIds, + ); + } catch (e) { + const responseErrors = await ErrorsHandler.getErrorMessages(e as Response); + enqueueSnackbar(responseErrors[0], { + variant: "warning", + autoHideDuration: 4000 + }); + onComplete(); + } + } + } + return { + filesState, + setFilesState, + handleFilesChange, + } +} diff --git a/hwproj.front/src/components/Files/FilesPreviewList.tsx b/hwproj.front/src/components/Files/FilesPreviewList.tsx index 58d8ea3a1..5013646e3 100644 --- a/hwproj.front/src/components/Files/FilesPreviewList.tsx +++ b/hwproj.front/src/components/Files/FilesPreviewList.tsx @@ -2,27 +2,39 @@ import {Grid} from "@mui/material"; import * as React from "react"; import FilePreview from "./FilePreview"; import {IFileInfo} from "./IFileInfo"; +import {DotLottieReact} from "@lottiefiles/dotlottie-react"; interface FilesPreviewProps { - filesInfo: IFileInfo[] + filesInfo: IFileInfo[] | undefined onRemoveFileInfo?: (f: IFileInfo) => void onClickFileInfo?: (f: IFileInfo) => void + showOkStatus?: boolean } const FilesPreviewList: React.FC = (props) => { return ( 4 ? -0.5 : 0.5} sx={{flexGrow: 1}}> - {props.filesInfo.map((fileInfo, index) => ( - - 4 ? -0.5 : 0.5} sx={{flexGrow: 1}}> + {props.filesInfo ? ( + props.filesInfo.map((fileInfo, index) => ( + + + ) + )) : ( +
+ - - ))} +
+ )}
) } diff --git a/hwproj.front/src/components/Files/FilesUploadWaiter.ts b/hwproj.front/src/components/Files/FilesUploadWaiter.ts new file mode 100644 index 000000000..e9f007821 --- /dev/null +++ b/hwproj.front/src/components/Files/FilesUploadWaiter.ts @@ -0,0 +1,181 @@ +import {useState, useEffect, useRef} from "react"; +import {FileInfoDTO, ScopeDTO} from "@/api"; +import {CourseUnitType} from "@/components/Files/CourseUnitType"; +import {enqueueSnackbar} from "notistack"; +import ApiSingleton from "@/api/ApiSingleton"; +import {FileStatus} from "@/components/Files/FileStatus"; +import ErrorsHandler from "@/components/Utils/ErrorsHandler"; + +export interface IUploadFilesState { + processingFilesState: { + [courseUnitId: number]: { + isLoading: boolean; + intervalId?: NodeJS.Timeout; + }; + }; + courseFiles: FileInfoDTO[]; +} + +export const FilesUploadWaiter = (courseId: number, courseUnitType: CourseUnitType, uploadedOnly: boolean) => { + const intervalsRef = useRef>({}); + + const [courseFilesState, setCourseFilesState] = useState({ + processingFilesState: {}, + courseFiles: [] + }) + + // Останавливаем все активные интервалы при размонтировании + useEffect(() => { + return () => { + Object.values(intervalsRef.current).forEach(({interval, timeout}) => { + clearInterval(interval); + clearTimeout(timeout); + }); + intervalsRef.current = {}; + }; + }, []); + + const stopProcessing = (courseUnitId: number) => { + if (intervalsRef.current[courseUnitId]) { + const {interval, timeout} = intervalsRef.current[courseUnitId]; + clearInterval(interval); + clearTimeout(timeout); + delete intervalsRef.current[courseUnitId]; + } + }; + + const setCommonLoading = (courseUnitId: number) => { + setCourseFilesState(prev => ({ + ...prev, + processingFilesState: { + ...prev.processingFilesState, + [courseUnitId]: {isLoading: true} + } + })); + } + + const unsetCommonLoading = (courseUnitId: number) => { + setCourseFilesState(prev => ({ + ...prev, + processingFilesState: { + ...prev.processingFilesState, + [courseUnitId]: {isLoading: false} + } + })); + } + + const updateFiles = async () => { + let courseFilesInfo = [] as FileInfoDTO[] + try { + courseFilesInfo = await ApiSingleton.filesApi.filesGetFilesInfo(+courseId!, uploadedOnly, courseUnitType) + } catch (e) { + const responseErrors = await ErrorsHandler.getErrorMessages(e as Response) + enqueueSnackbar(responseErrors[0], {variant: "warning", autoHideDuration: 1990}); + } + setCourseFilesState(prevState => ({ + ...prevState, + courseFiles: courseFilesInfo + })) + } + + useEffect(() => { + updateFiles(); + }, [courseId, uploadedOnly, courseUnitType]); + + const updateCourseUnitFilesInfo = (files: FileInfoDTO[], unitType: CourseUnitType, unitId: number) => { + setCourseFilesState(prev => ({ + ...prev, + courseFiles: [ + ...prev.courseFiles.filter( + f => !(f.courseUnitType === unitType && f.courseUnitId === unitId)), + ...files + ] + })); + }; + + // Запускает получение информации о файлах элемента курса с интервалом в 1 секунду и 5 попытками + const updateCourseUnitFiles = + (courseUnitId: number, + courseUnitType: CourseUnitType, + previouslyExistingFilesCount: number, + waitingNewFilesCount: number, + deletingFilesIds: number[] + ) => { + // Очищаем предыдущие таймеры + stopProcessing(courseUnitId); + + let attempt = 0; + const maxAttempts = 10; + let delay = 1000; // Начальная задержка 1 сек + + const scopeDto: ScopeDTO = { + courseId: +courseId!, + courseUnitType: courseUnitType, + courseUnitId: courseUnitId + } + + const fetchFiles = async () => { + if (attempt >= maxAttempts) { + stopProcessing(courseUnitId); + enqueueSnackbar("Превышено допустимое количество попыток получения информации о файлах", { + variant: "warning", + autoHideDuration: 2000 + }); + return; + } + + attempt++; + try { + const files = await ApiSingleton.filesApi.filesGetStatuses(scopeDto); + console.log(`Попытка ${attempt}:`, files); + + // Первый вариант для явного отображения всех файлов + if (waitingNewFilesCount === 0 + && files.filter(f => f.status === FileStatus.ReadyToUse).length === previouslyExistingFilesCount - deletingFilesIds.length) { + updateCourseUnitFilesInfo(files, scopeDto.courseUnitType as CourseUnitType, scopeDto.courseUnitId!) + unsetCommonLoading(courseUnitId) + } + + // Второй вариант для явного отображения всех файлов + if (waitingNewFilesCount > 0 + && files.filter(f => !deletingFilesIds.some(dfi => dfi === f.id)).length === previouslyExistingFilesCount - deletingFilesIds.length + waitingNewFilesCount) { + updateCourseUnitFilesInfo(files, scopeDto.courseUnitType as CourseUnitType, scopeDto.courseUnitId!) + unsetCommonLoading(courseUnitId) + } + + // Условие прекращения отправки запросов на получения записей файлов + if (files.length === previouslyExistingFilesCount - deletingFilesIds.length + waitingNewFilesCount + && files.every(f => f.status !== FileStatus.Uploading && f.status !== FileStatus.Deleting)) { + stopProcessing(courseUnitId); + unsetCommonLoading(courseUnitId) + } + + } catch (error) { + console.error(`Ошибка (попытка ${attempt}):`, error); + } + } + // Создаем интервал с задержкой + const interval = setInterval(fetchFiles, delay); + + // Создаем таймаут для автоматической остановки + const timeout = setTimeout(() => { + stopProcessing(courseUnitId); + unsetCommonLoading(courseUnitId); + }, 10000); + + // Сохраняем интервал и таймаут в ref + intervalsRef.current[courseUnitId] = {interval, timeout}; + + // Сигнализируем о начале загрузки через состояние + setCommonLoading(courseUnitId); + } + + return { + courseFilesState, + updateFiles, + updateCourseUnitFiles, + } +} diff --git a/hwproj.front/src/components/Files/FilesUploader.tsx b/hwproj.front/src/components/Files/FilesUploader.tsx index 078fc603b..190543a9a 100644 --- a/hwproj.front/src/components/Files/FilesUploader.tsx +++ b/hwproj.front/src/components/Files/FilesUploader.tsx @@ -1,16 +1,24 @@ import {Box, Snackbar} from "@material-ui/core"; -import CloudUploadIcon from "@mui/icons-material/CloudUpload"; +import {FileUploader} from "react-drag-drop-files"; import * as React from "react"; import {styled} from "@mui/material/styles"; import {useEffect, useState} from "react"; import {IFileInfo} from "./IFileInfo"; -import {Alert, Button, Grid} from "@mui/material"; +import {Alert, Card, CardContent, Grid, Stack, Typography} from "@mui/material"; import FilesPreviewList from "./FilesPreviewList"; +import {CourseUnitType} from "./CourseUnitType"; +import {FileStatus} from "./FileStatus"; +import CloudUploadOutlinedIcon from '@mui/icons-material/CloudUploadOutlined'; +import "./filesUploaderOverrides.css"; +import Utils from "@/services/Utils"; interface IFilesUploaderProps { + courseUnitType: CourseUnitType + courseUnitId: number; initialFilesInfo?: IFileInfo[]; onChange: (selectedFiles: IFileInfo[]) => void; isLoading?: boolean; + maxFilesCount?: number; } // Кастомизированный Input для загрузки файла (из примеров MaterialUI) @@ -37,40 +45,56 @@ const FilesUploader: React.FC = (props) => { } }, [props.initialFilesInfo]); - const validFileNameRegex = /^(?!.*[:*?"<>|!])[\p{L}0-9_\-\.() ]+(\.[\p{L}0-9]+)?$/u; const maxFileSizeInBytes = 100 * 1024 * 1024; - const validateFiles = (files: FileList): boolean => { - for (const file of files) { - const isValidName = validFileNameRegex.test(file.name); - if (!isValidName) { - setError(`Недопустимое имя файла: ${file.name}. - Пожалуйста, используйте буквы, цифры, символы _ - . ( ) : или пробел`); - return false; - } + const forbiddenFileTypes = [ + 'application/vnd.microsoft.portable-executable', + 'application/x-msdownload', + 'application/x-ms-installer', + 'application/x-ms-dos-executable', + 'application/x-dosexec', + 'application/x-msdos-program', + 'application/octet-stream', // если тип двоичного файла не определен, отбрасывать + ] + const validateFiles = (files: File[]): boolean => { + if (props.maxFilesCount && + (props.initialFilesInfo ? props.initialFilesInfo.length : 0) + files.length > props.maxFilesCount) { + setError(`Выбрано слишком много файлов. + Максимально допустимое количество файлов: ${props.maxFilesCount} ${Utils.pluralizeHelper(["штука", "штука", "штук"], props.maxFilesCount)}`); + return false; + } + for (const file of files) { if (file.size > maxFileSizeInBytes) { setError(`Файл "${file.name}" слишком большой. Максимальный допустимый размер: ${(maxFileSizeInBytes / 1024 / 1024).toFixed(1)} MB.`); return false; } + if (forbiddenFileTypes.includes(file.type)) { + setError(`Файл "${file.name}" имеет недопустимый тип "${file.type}`); + return false; + } } return true } - const handleFileInputChange = (e: React.ChangeEvent) => { - if (e.target.files == null) return - if (!validateFiles(e.target.files)) return + const handleFileInputChange = (input: Array | File) => { + const files = input instanceof File ? [input] : input; + if (files == null) return + if (!validateFiles(files)) return const newFilesInfo: IFileInfo[] = [] - for (const file of e.target.files) { + for (const file of files) { newFilesInfo.push({ name: file.name, type: file.type, sizeInBytes: file.size, - file: file + file: file, + courseUnitType: props.courseUnitType, + courseUnitId: props.courseUnitId, + status: FileStatus.Local }) } setSelectedFilesInfo(previouslySelected => { @@ -81,7 +105,7 @@ const FilesUploader: React.FC = (props) => { } return ( - + {error && ( = (props) => { {error} )} - - + + + + + {props.courseUnitType === CourseUnitType.Solution + ? "Загрузите файлы решения" + : "Загрузите материалы задания"} + + + + } + multiple={true} + name="file"/> {props.isLoading && @@ -118,12 +148,12 @@ const FilesUploader: React.FC = (props) => { } - + { setSelectedFilesInfo(previouslySelected => { - const updatedArray = previouslySelected.filter(f => f.name !== fI.name); + const updatedArray = previouslySelected.filter(f => f.name !== fI.name || f.id !== fI.id); props.onChange(updatedArray); return updatedArray; }); diff --git a/hwproj.front/src/components/Files/IFileInfo.ts b/hwproj.front/src/components/Files/IFileInfo.ts index de65d27ca..e2d7607ae 100644 --- a/hwproj.front/src/components/Files/IFileInfo.ts +++ b/hwproj.front/src/components/Files/IFileInfo.ts @@ -1,7 +1,13 @@ +import { CourseUnitType } from "./CourseUnitType"; +import { FileStatus } from "./FileStatus"; + export interface IFileInfo { + id?: number; file?: File; type?: string; + status: FileStatus; name: string; sizeInBytes: number; - key?: string; + courseUnitType: CourseUnitType, + courseUnitId: number; } diff --git a/hwproj.front/src/components/Files/IProcessFilesDto.ts b/hwproj.front/src/components/Files/IProcessFilesDto.ts new file mode 100644 index 000000000..492538502 --- /dev/null +++ b/hwproj.front/src/components/Files/IProcessFilesDto.ts @@ -0,0 +1,9 @@ +import { CourseUnitType } from "./CourseUnitType"; + +export interface IProcessFilesDto { + courseId: number, + courseUnitType: CourseUnitType, + courseUnitId: number, + deletingFileIds: number[], + newFiles: File[] +} \ No newline at end of file diff --git a/hwproj.front/src/components/Files/filesUploaderOverrides.css b/hwproj.front/src/components/Files/filesUploaderOverrides.css new file mode 100644 index 000000000..12c61d60a --- /dev/null +++ b/hwproj.front/src/components/Files/filesUploaderOverrides.css @@ -0,0 +1,4 @@ +/* Overrides for react-drag-drop-files FileUploader to prevent the hidden input from being block-level */ +.rddu-no-block { + display: inline !important; /* make input non-blocking */ +} diff --git a/hwproj.front/src/components/Homeworks/CourseHomeworkExperimental.tsx b/hwproj.front/src/components/Homeworks/CourseHomeworkExperimental.tsx index 55741604d..cfd7dbadd 100644 --- a/hwproj.front/src/components/Homeworks/CourseHomeworkExperimental.tsx +++ b/hwproj.front/src/components/Homeworks/CourseHomeworkExperimental.tsx @@ -1,27 +1,45 @@ -import {CardActions, CardContent, Chip, Divider, Grid, IconButton, TextField, Typography} from "@mui/material"; +import { + Alert, + CardActions, + CardContent, + Chip, + CircularProgress, + Divider, + Grid, + IconButton, + Stack, + TextField, + Tooltip, + Typography +} from "@mui/material"; import {MarkdownEditor, MarkdownPreview} from "components/Common/MarkdownEditor"; import FilesPreviewList from "components/Files/FilesPreviewList"; import {IFileInfo} from "components/Files/IFileInfo"; import {FC, useEffect, useState} from "react" import Utils from "services/Utils"; -import {FileInfoDTO, HomeworkViewModel, ActionOptions} from "../../api"; +import { + HomeworkViewModel, ActionOptions, HomeworkTaskViewModel, PostTaskViewModel +} from "@/api"; import ApiSingleton from "../../api/ApiSingleton"; -import UpdateFilesUtils from "../Utils/UpdateFilesUtils"; import Tags from "../Common/Tags"; import apiSingleton from "../../api/ApiSingleton"; import FilesUploader from "../Files/FilesUploader"; import PublicationAndDeadlineDates from "../Common/PublicationAndDeadlineDates"; import * as React from "react"; import EditIcon from "@mui/icons-material/Edit"; +import AddTaskIcon from '@mui/icons-material/AddTask'; import {LoadingButton} from "@mui/lab"; -import ErrorsHandler from "../Utils/ErrorsHandler"; -import {enqueueSnackbar} from "notistack"; import DeletionConfirmation from "../DeletionConfirmation"; import DeleteIcon from "@mui/icons-material/Delete"; import ActionOptionsUI from "components/Common/ActionOptions"; +import {BonusTag, DefaultTags, isBonusWork, isTestWork, TestTag} from "@/components/Common/HomeworkTags"; +import Lodash from "lodash"; +import {CourseUnitType} from "../Files/CourseUnitType" +import ProcessFilesUtils from "../Utils/ProcessFilesUtils"; +import {FilesHandler} from "@/components/Files/FilesHandler"; export interface HomeworkAndFilesInfo { - homework: HomeworkViewModel, + homework: HomeworkViewModel & { isModified?: boolean }, filesInfo: IFileInfo[] } @@ -30,78 +48,159 @@ interface IEditHomeworkState { hasDeadline: boolean; deadlineDate?: Date; isDeadlineStrict: boolean; -} - -interface IEditFilesState { - initialFilesInfo: IFileInfo[] - selectedFilesInfo: IFileInfo[] - isLoadingInfo: boolean + hasErrors: boolean; } const CourseHomeworkEditor: FC<{ homeworkAndFilesInfo: HomeworkAndFilesInfo, - onUpdate: (update: { homework: HomeworkViewModel, fileInfos: FileInfoDTO[] } & { isDeleted?: boolean }) => void + getAllHomeworks: () => HomeworkViewModel[], + onUpdate: (update: { homework: HomeworkViewModel } & { + isDeleted?: boolean, + isSaved?: boolean + }) => void + onStartProcessing: (homeworkId: number, + courseUnitType: CourseUnitType, + previouslyExistingFilesCount: number, + waitingNewFilesCount: number, + deletingFilesIds: number[]) => void; }> = (props) => { - const speculativeHomework = props.homeworkAndFilesInfo.homework + const homework = props.homeworkAndFilesInfo.homework + const isNewHomework = homework.id! < 0 const [homeworkData, setHomeworkData] = useState<{ - homework: HomeworkViewModel, + loadedHomework: HomeworkViewModel, isLoaded: boolean - }>({homework: speculativeHomework, isLoaded: false}) + }>({loadedHomework: homework, isLoaded: isNewHomework || homework.isModified == true}) useEffect(() => { + if (homeworkData.isLoaded) return ApiSingleton.homeworksApi - .homeworksGetForEditingHomework(speculativeHomework.id!) - .then(homework => setHomeworkData({homework, isLoaded: true})) + .homeworksGetForEditingHomework(homework.id!) + .then(homework => setHomeworkData({loadedHomework: homework, isLoaded: true})) }, []) - const {homework, isLoaded} = homeworkData + const {loadedHomework, isLoaded} = homeworkData + + const {filesState, setFilesState, handleFilesChange} = FilesHandler(props.homeworkAndFilesInfo.filesInfo) + const initialFilesInfo = props.homeworkAndFilesInfo.filesInfo.filter(x => x.id !== undefined) - const filesInfo = props.homeworkAndFilesInfo.filesInfo - const homeworkId = homework.id! - const courseId = homework.courseId! + const homeworkId = loadedHomework.id! + const courseId = loadedHomework.courseId! - const publicationDate = homework.publicationDateNotSet + const publicationDate = loadedHomework.publicationDateNotSet || !loadedHomework.publicationDate ? undefined - : new Date(homework.publicationDate!) + : new Date(loadedHomework.publicationDate!) - const deadlineDate = homework.deadlineDateNotSet + const deadlineDate = loadedHomework.deadlineDateNotSet || !loadedHomework.deadlineDate ? undefined - : new Date(homework.deadlineDate!) + : new Date(loadedHomework.deadlineDate!) - const isPublished = !homework.isDeferred - const changedTaskPublicationDates = homework.tasks! + const isPublished = !loadedHomework.isDeferred + const changedTaskPublicationDates = loadedHomework.tasks! .filter(t => t.publicationDate != null) .map(t => new Date(t.publicationDate!)) + const taskHasErrors = homework.tasks!.some((x: HomeworkTaskViewModel & { + hasErrors?: boolean + }) => x.hasErrors === true) + const [metadata, setMetadata] = useState({ publicationDate: publicationDate, - hasDeadline: homework.hasDeadline!, + hasDeadline: loadedHomework.hasDeadline!, deadlineDate: deadlineDate, - isDeadlineStrict: homework.isDeadlineStrict!, + isDeadlineStrict: loadedHomework.isDeadlineStrict!, + hasErrors: false, }) - const [title, setTitle] = useState(homework.title!) - const [tags, setTags] = useState(homework.tags!) - const [description, setDescription] = useState(homework.description!) - const [filesControlState, setFilesControlState] = useState({ - initialFilesInfo: filesInfo, - selectedFilesInfo: filesInfo, - isLoadingInfo: false - }); + const [title, setTitle] = useState(loadedHomework.title!) + const [tags, setTags] = useState(loadedHomework.tags!) + const [description, setDescription] = useState(loadedHomework.description!) + const [hasErrors, setHasErrors] = useState(false) const [handleSubmitLoading, setHandleSubmitLoading] = useState(false) const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false) const [editOptions, setEditOptions] = useState({sendNotification: false}) + const [deadlineSuggestion, setDeadlineSuggestion] = useState(undefined) + const [tagSuggestion, setTagSuggestion] = useState(undefined) + + useEffect(() => { + if (!isNewHomework || !metadata.publicationDate) return + const isTest = tags.includes(TestTag) + const isBonus = tags.includes(BonusTag) + + const dateCandidate = Lodash(props.getAllHomeworks() + .filter(x => { + const xIsTest = isTestWork(x) + const xIsBonus = isBonusWork(x) + return x.id! > 0 && x.hasDeadline && (isTest && xIsTest || isBonus && xIsBonus || !isTest && !isBonus && !xIsTest && !xIsBonus) + }) + .map(x => { + const deadlineDate = new Date(x.deadlineDate!) + return ({ + deadlineDate: deadlineDate, + daysDiff: Math.floor((deadlineDate.getTime() - new Date(x.publicationDate!).getTime()) / (1000 * 3600 * 24)) + }); + })) + .groupBy(x => [x.daysDiff, x.deadlineDate.getHours(), x.deadlineDate.getMinutes()]) + .entries() + .sortBy(x => x[1].length).last()?.[1][0] + if (dateCandidate) { + const publicationDate = new Date(metadata.publicationDate) + const dateTime = dateCandidate.deadlineDate + publicationDate.setDate(publicationDate.getDate() + dateCandidate.daysDiff) + publicationDate.setHours(dateTime.getHours(), dateTime.getMinutes(), 0, 0) + setDeadlineSuggestion(publicationDate) + } else { + setDeadlineSuggestion(undefined) + } + }, [tags, metadata.publicationDate]) + + useEffect(() => { + const update = { + ...homework, + ...metadata, + tasks: homework.tasks, + title: title, + description: description, + tags: tags, + hasErrors: hasErrors, + deadlineDateNotSet: metadata.hasDeadline && !metadata.deadlineDate, + isModified: true, + } + + props.onUpdate({homework: update}) + }, [title, description, tags, metadata, hasErrors, filesState.selectedFilesInfo]) + + useEffect(() => { + setHasErrors(!title || metadata.hasErrors) + }, [title, metadata.hasErrors]) + + useEffect(() => { + const x = title.toLowerCase() + setTagSuggestion( + !tags.includes(TestTag) && ( + x.includes("контрольн") || + x.includes("проверочн") || + x.includes("переписывание") || + x.includes("тест")) + ? TestTag : undefined) + }, [title, tags]); + const deleteHomework = async () => { - await ApiSingleton.homeworksApi.homeworksDeleteHomework(homeworkId) + if (!isNewHomework) await ApiSingleton.homeworksApi.homeworksDeleteHomework(homeworkId) - // Удаляем файлы домашней работы из хранилища - const deleteOperations = filesInfo.map(initialFile => UpdateFilesUtils.deleteFileWithErrorsHadling(courseId!, initialFile)) - await Promise.all(deleteOperations) + // Удаляем файлы домашней работы с сервера + var deletingFileIds = initialFilesInfo.filter(fileInfo => fileInfo.id).map(fileInfo => fileInfo.id!) + await ProcessFilesUtils.processFilesWithErrorsHadling({ + courseId: courseId!, + courseUnitType: CourseUnitType.Homework, + courseUnitId: homeworkId, + deletingFileIds: deletingFileIds, + newFiles: [] + }) - props.onUpdate({homework, fileInfos: [], isDeleted: true}) + props.onUpdate({homework: loadedHomework, isDeleted: true}) } const getDeleteMessage = (homeworkName: string, filesInfo: IFileInfo[]) => { @@ -119,7 +218,9 @@ const CourseHomeworkEditor: FC<{ const handleSubmit = async (e: any) => { e.preventDefault() setHandleSubmitLoading(true) - const updatedHomework = await ApiSingleton.homeworksApi.homeworksUpdateHomework(+homeworkId!, { + + const update = { + homeworkId: homeworkId, title: title!, description: description, tags: tags, @@ -128,52 +229,40 @@ const CourseHomeworkEditor: FC<{ isDeadlineStrict: metadata.isDeadlineStrict, publicationDate: metadata.publicationDate, actionOptions: editOptions, - }) - - // Если какие-то файлы из ранее добавленных больше не выбраны, удаляем их из хранилища - const deleteOperations = filesControlState.initialFilesInfo - .filter(initialFile => - initialFile.key && - !filesControlState.selectedFilesInfo.some(s => s.key === initialFile.key) - ) - .map(initialFile => UpdateFilesUtils.deleteFileWithErrorsHadling(courseId, initialFile)); - - // Если какие-то файлы из выбранных сейчас не были добавлены раньше, загружаем их в хранилище - const uploadOperations = filesControlState.selectedFilesInfo - .filter(selectedFile => - selectedFile.file && - !filesControlState.initialFilesInfo.some(i => i.key === selectedFile.key) - ) - .map(selectedFile => UpdateFilesUtils.uploadFileWithErrorsHadling( - selectedFile.file!, - courseId, - +homeworkId!) - ); - - // Дожидаемся удаления и загрузки необходимых файлов - await Promise.all([...deleteOperations, ...uploadOperations]) - - if (deleteOperations.length === 0 && uploadOperations.length === 0) { - props.onUpdate({homework: updatedHomework.value!, fileInfos: filesControlState.selectedFilesInfo}) - } else { - try { - const newFilesDtos = await ApiSingleton.filesApi.filesGetFilesInfo(courseId, homeworkId!) - props.onUpdate({homework: updatedHomework.value!, fileInfos: newFilesDtos}) - } catch (e) { - const responseErrors = await ErrorsHandler.getErrorMessages(e as Response) - enqueueSnackbar(responseErrors[0], {variant: "warning", autoHideDuration: 4000}); - props.onUpdate({homework: updatedHomework.value!, fileInfos: filesControlState.selectedFilesInfo}) - } + tasks: isNewHomework ? homework.tasks!.map(t => { + const task: PostTaskViewModel = { + ...t, + title: t.title!, + maxRating: t.maxRating! + } + return task + }) : [] } + + const updatedHomework = isNewHomework + ? await ApiSingleton.homeworksApi.homeworksAddHomework(courseId!, update) + : await ApiSingleton.homeworksApi.homeworksUpdateHomework(+homeworkId!, update) + + const updatedHomeworkId = updatedHomework.value!.id! + await handleFilesChange( + courseId, CourseUnitType.Homework, updatedHomeworkId, + props.onStartProcessing, + () => { + if (isNewHomework) props.onUpdate({ + homework: update, + isDeleted: true + }) // remove fake homework + props.onUpdate({homework: updatedHomework.value!, isSaved: true}); + }, + ); } - const isSomeTaskSoonerThanHomework = changedTaskPublicationDates.some(d => d < metadata.publicationDate!) - const isDisabled = isSomeTaskSoonerThanHomework || hasErrors || !isLoaded + const isDisabled = hasErrors || !isLoaded || taskHasErrors return ( + alignItems={"center"} alignContent={"center"} style={{marginTop: -20}}> { e.persist() + setHasErrors(prevState => prevState || !e.target.value) setTitle(e.target.value) }} /> - setTags(newTags)} isElementSmall={false} + apiSingleton.coursesApi.coursesGetAllTagsForCourse(courseId)}/> + {tags.includes(TestTag) && + + + Вы можете сгруппировать контрольные работы и переписывания с помощью + дополнительного тега. Например, 'КР 1' + + } { - setFilesControlState((prevState) => ({ + setFilesState((prevState) => ({ ...prevState, selectedFilesInfo: filesInfo - })) + })); }} - /> + courseUnitType={CourseUnitType.Homework} + courseUnitId={homeworkId}/> { + const conflictsWithTasks = changedTaskPublicationDates.some(d => d < metadata.publicationDate!) setMetadata({ hasDeadline: state.hasDeadline, isDeadlineStrict: state.isDeadlineStrict, publicationDate: state.publicationDate, deadlineDate: state.deadlineDate, + hasErrors: state.hasErrors || conflictsWithTasks, }) - setHasErrors(state.hasErrors) }} /> + {taskHasErrors && + Одна или более вложенных задач содержат ошибки + } {metadata.publicationDate && new Date() >= new Date(metadata.publicationDate) && } loading={handleSubmitLoading} > - Редактировать задание ({editOptions.sendNotification ? "с уведомлением" : "без уведомления"}) + {isNewHomework && "Добавить задание"} + {!isNewHomework && "Редактировать задание " + (editOptions.sendNotification ? "с уведомлением" : "без уведомления")} setShowDeleteConfirmation(true)}> @@ -265,7 +370,7 @@ const CourseHomeworkEditor: FC<{ onSubmit={deleteHomework} isOpen={showDeleteConfirmation} dialogTitle={'Удаление задания'} - dialogContentText={getDeleteMessage(homework.title!, filesInfo)} + dialogContentText={getDeleteMessage(homework.title!, initialFilesInfo)} confirmationWord={''} confirmationText={''} /> @@ -275,13 +380,23 @@ const CourseHomeworkEditor: FC<{ const CourseHomeworkExperimental: FC<{ homeworkAndFilesInfo: HomeworkAndFilesInfo, + getAllHomeworks: () => HomeworkViewModel[], isMentor: boolean, initialEditMode: boolean, onMount: () => void, - onUpdate: (x: { homework: HomeworkViewModel, fileInfos: FileInfoDTO[] } & { isDeleted?: boolean }) => void + onUpdate: (x: { homework: HomeworkViewModel } & { + isDeleted?: boolean + }) => void + onAddTask: (homework: HomeworkViewModel) => void, + isProcessing: boolean; + onStartProcessing: (homeworkId: number, + courseUnitType: CourseUnitType, + previouslyExistingFilesCount: number, + waitingNewFilesCount: number, + deletingFilesIds: number[]) => void; }> = (props) => { const {homework, filesInfo} = props.homeworkAndFilesInfo - const deferredHomeworks = homework.tasks!.filter(t => t.isDeferred!) + const deferredTasks = homework.tasks!.filter(t => t.isDeferred!) const tasksCount = homework.tasks!.length const [showEditMode, setShowEditMode] = useState(false) const [editMode, setEditMode] = useState(false) @@ -292,61 +407,77 @@ const CourseHomeworkExperimental: FC<{ }, [homework.id]) if (editMode) return { - setEditMode(false) + if (update.isSaved) setEditMode(false) props.onUpdate(update) }} + onStartProcessing={props.onStartProcessing} /> return setShowEditMode(props.isMentor)} onMouseLeave={() => setShowEditMode(false)}> - - + {homework.title} - {props.isMentor && deferredHomeworks!.length > 0 && - - } {tasksCount > 0 && + label={tasksCount + " " + + Utils.pluralizeHelper(["Задача", "Задачи", "Задач"], tasksCount) + + (deferredTasks!.length > 0 ? ` (🕘 ${deferredTasks.length} ` + Utils.pluralizeHelper(["отложенная", "отложенные", "отложенных"], deferredTasks.length) + ")" : "")}/> } - {homework.tags?.filter(t => t !== '').map((tag, index) => ( + {homework.tags?.filter(t => DefaultTags.includes(t)).map((tag, index) => ( ))} {showEditMode && - { - setEditMode(true) - setShowEditMode(false) - }}> - - + + + props.onAddTask(homework)} + > + + + + { + setEditMode(true) + setShowEditMode(false) + }}> + + + } - { - filesInfo && filesInfo.length > 0 && + {props.isProcessing ? ( +
+ +   Обрабатываем файлы... +
+ ) : filesInfo.length > 0 && (
{ - const url = await ApiSingleton.customFilesApi.getDownloadFileLink(fileInfo.key!) + const url = await ApiSingleton.customFilesApi.getDownloadFileLink(fileInfo.id!); window.open(url, '_blank'); }} />
+ ) }
} diff --git a/hwproj.front/src/components/Solutions/AddOrEditSolution.tsx b/hwproj.front/src/components/Solutions/AddOrEditSolution.tsx index 37c067dc6..581d53d8c 100644 --- a/hwproj.front/src/components/Solutions/AddOrEditSolution.tsx +++ b/hwproj.front/src/components/Solutions/AddOrEditSolution.tsx @@ -1,52 +1,87 @@ import * as React from 'react'; -import TextField from '@material-ui/core/TextField'; -import Button from '@material-ui/core/Button' +import {FC, useState} from 'react'; import ApiSingleton from "../../api/ApiSingleton"; -import {AccountDataDto, GetSolutionModel, HomeworkTaskViewModel, SolutionState, SolutionViewModel} from "../../api"; -import {FC, useState} from "react"; -import {Alert, Autocomplete, Grid, DialogContent, Dialog, DialogTitle, DialogActions} from "@mui/material"; +import { + AccountDataDto, + FileInfoDTO, + GetSolutionModel, + HomeworkTaskViewModel, + PostSolutionModel, + SolutionState, +} from "@/api"; +import {Alert, Autocomplete, Button, Dialog, DialogActions, DialogContent, DialogTitle, Grid} from "@mui/material"; import {MarkdownEditor} from "../Common/MarkdownEditor"; import {TestTag} from "../Common/HomeworkTags"; +import {LoadingButton} from "@mui/lab"; +import TextField from "@mui/material/TextField"; +import FilesUploader from '../Files/FilesUploader'; +import {CourseUnitType} from '../Files/CourseUnitType'; +import ErrorsHandler from "@/components/Utils/ErrorsHandler"; +import {enqueueSnackbar} from "notistack"; +import FileInfoConverter from "@/components/Utils/FileInfoConverter"; +import {FilesHandler} from "@/components/Files/FilesHandler"; interface IAddSolutionProps { + courseId: number userId: string lastSolution: GetSolutionModel | undefined, task: HomeworkTaskViewModel, supportsGroup: boolean, - students: AccountDataDto[] + students: AccountDataDto[], + courseFilesInfo: FileInfoDTO[], onAdd: () => void, onCancel: () => void, + onStartProcessing: (solutionId: number, + courseUnitType: CourseUnitType, + previouslyExistingFilesCount: number, + waitingNewFilesCount: number, + deletingFilesIds: number[]) => void, } const AddOrEditSolution: FC = (props) => { - const {lastSolution} = props + const { lastSolution } = props const isEdit = lastSolution?.state === SolutionState.NUMBER_0 const lastGroup = lastSolution?.groupMates?.map(x => x.userId!) || [] - const [solution, setSolution] = useState({ + const [solution, setSolution] = useState({ githubUrl: lastSolution?.githubUrl || "", comment: isEdit ? lastSolution!.comment : "", groupMateIds: lastGroup }) + const [disableSend, setDisableSend] = useState(false) + + const maxFilesCount = 5; + + const filesInfo = lastSolution?.id ? FileInfoConverter.getCourseUnitFilesInfo(props.courseFilesInfo, CourseUnitType.Solution, lastSolution.id) : [] + const {filesState, setFilesState, handleFilesChange} = FilesHandler(filesInfo); + const handleSubmit = async (e: any) => { e.preventDefault(); - await ApiSingleton.solutionsApi.solutionsPostSolution(props.task.id!, solution) - props.onAdd() + setDisableSend(true) + + let solutionId = await ApiSingleton.solutionsApi.solutionsPostSolution(props.task.id!, solution) + await handleFilesChange(props.courseId, CourseUnitType.Solution, solutionId, + props.onStartProcessing, + props.onAdd + ); } - const {githubUrl} = solution + const { githubUrl } = solution const isTest = props.task.tags?.includes(TestTag) const showTestGithubInfo = isTest && githubUrl?.startsWith("https://github") && githubUrl.includes("/pull/") const courseMates = props.students.filter(s => props.userId !== s.userId) return ( - props.onCancel()} aria-labelledby="form-dialog-title"> + props.onCancel()} aria-labelledby="form-dialog-title"> Отправить новое решение - + = (props) => { }} /> {showTestGithubInfo && - + Для данного решения будет сохранена информация о коммитах на момент отправки. -
+
Убедитесь, что работа закончена, и отправьте решение в конце.
} {!isEdit && githubUrl === lastSolution?.githubUrl && !showTestGithubInfo && - Ссылка + Ссылка взята из предыдущего решения}
- {props.supportsGroup && + {props.supportsGroup && = (props) => { )} /> {!isEdit && lastGroup?.length > 0 && solution.groupMateIds === lastGroup && - Команда + Команда взята из предыдущего решения} } - + { setSolution((prevState) => ({ ...prevState, @@ -111,27 +147,41 @@ const AddOrEditSolution: FC = (props) => { })) }} /> + { + setFilesState((prevState) => ({ + ...prevState, + selectedFilesInfo: filesInfo + })); + }} + courseUnitType={CourseUnitType.Solution} + courseUnitId={lastSolution?.id !== undefined ? lastSolution.id : -1} + maxFilesCount={maxFilesCount} + />
- - + }
) diff --git a/hwproj.front/src/components/Solutions/StudentSolutionsPage.tsx b/hwproj.front/src/components/Solutions/StudentSolutionsPage.tsx index 1fa5188ea..57a5d7c14 100644 --- a/hwproj.front/src/components/Solutions/StudentSolutionsPage.tsx +++ b/hwproj.front/src/components/Solutions/StudentSolutionsPage.tsx @@ -1,17 +1,20 @@ import * as React from "react"; import {FC, useEffect, useState} from "react"; import { - GetSolutionModel, HomeworksGroupSolutionStats, + AccountDataDto, + GetSolutionModel, + HomeworksGroupSolutionStats, HomeworkTaskViewModel, Solution, - TaskSolutionsStats, - SolutionState, StudentDataDto -} from "../../api/"; + SolutionState, + StudentDataDto, + TaskSolutionsStats +} from "@/api"; import Typography from "@material-ui/core/Typography"; import Task from "../Tasks/Task"; import TaskSolutions from "./TaskSolutions"; import ApiSingleton from "../../api/ApiSingleton"; -import {Grid, Tabs, Tab} from "@material-ui/core"; +import {Grid, Tab, Tabs} from "@material-ui/core"; import {Link, useNavigate, useParams} from "react-router-dom"; import TaskAltIcon from '@mui/icons-material/TaskAlt'; import EditIcon from '@mui/icons-material/Edit'; @@ -19,14 +22,16 @@ import ThumbUpIcon from '@mui/icons-material/ThumbUp'; import ThumbDownIcon from '@mui/icons-material/ThumbDown'; import { Alert, + Autocomplete, + Checkbox, Chip, List, ListItemButton, ListItemText, SelectChangeEvent, Stack, - Tooltip, - Checkbox + TextField, + Tooltip } from "@mui/material"; import StudentStatsUtils from "../../services/StudentStatsUtils"; @@ -36,16 +41,21 @@ import {RatingStorage} from "../Storages/RatingStorage"; import {getTip} from "../Common/HomeworkTags"; import {appBarStateManager} from "../AppBar"; import {DotLottieReact} from "@lottiefiles/dotlottie-react"; +import {RemovedFromCourseTag} from "@/components/Common/StudentTags"; +import {FilesUploadWaiter} from "@/components/Files/FilesUploadWaiter"; +import {CourseUnitType} from "@/components/Files/CourseUnitType"; interface IStudentSolutionsPageState { currentTaskId: string task: HomeworkTaskViewModel isLoaded: boolean courseId: number, + courseMentors: AccountDataDto[], homeworkSolutionsStats: HomeworksGroupSolutionStats[], taskStudentsSolutionsPreview: { taskId: number, studentSolutionsPreview: { + hasDifferentReviewer: boolean, student: StudentDataDto, solutions: GetSolutionModel[] lastSolution: GetSolutionModel, @@ -78,14 +88,18 @@ const StudentSolutionsPage: FC = () => { const [studentSolutionsState, setStudentSolutionsState] = useState({ currentTaskId: "", task: {}, + courseMentors: [], isLoaded: false, courseId: -1, homeworkSolutionsStats: [], taskStudentsSolutionsPreview: [], }) - const [filterState, setFilterState] = React.useState( - localStorage.getItem(FilterStorageKey)?.split(", ").filter(x => x !== "").map(x => x as Filter) || ["Только непроверенные"] + const [filterState, setFilterState] = useState( + localStorage.getItem(FilterStorageKey)?.split(", ").filter(x => x !== "").map(x => x as Filter) || [] ) + + const [secondMentorId, setSecondMentorId] = useState(undefined) + const handleFilterChange = (event: SelectChangeEvent) => { const filters = filterState.length > 0 ? [] : ["Только непроверенные" as Filter] localStorage.setItem(FilterStorageKey, filters.join(", ")) @@ -99,9 +113,12 @@ const StudentSolutionsPage: FC = () => { currentTaskId, taskStudentsSolutionsPreview, courseId, - homeworkSolutionsStats + homeworkSolutionsStats, + courseMentors } = studentSolutionsState + const secondMentor = courseMentors.find(x => x.userId == secondMentorId) + const currentTaskSolutionsPreview = taskStudentsSolutionsPreview.find(x => x.taskId === +currentTaskId) const currentTaskSolutions = currentTaskSolutionsPreview?.studentSolutionsPreview || [] @@ -121,14 +138,15 @@ const StudentSolutionsPage: FC = () => { }) const taskSolutionsStats = showOnlyUnrated - ? allTaskSolutionsStats.filter(x => x.countUnratedSolutions && x.countUnratedSolutions > 0) + ? allTaskSolutionsStats.filter(x => x.taskId == +currentTaskId || x.countUnratedSolutions && x.countUnratedSolutions > 0) : allTaskSolutionsStats const studentSolutionsPreviews = taskStudentsSolutionsPreview.map(x => showOnlyUnrated ? ({ taskId: x.taskId, - studentSolutionsPreview: x.studentSolutionsPreview.filter(((_, i) => { + studentSolutionsPreview: x.studentSolutionsPreview.filter(((data, i) => { + if (data.student.userId === currentStudentId) return true const lastSolution = currentTaskSolutions[i].lastSolution return lastSolution && lastSolution.state === SolutionState.NUMBER_0 })) @@ -155,8 +173,8 @@ const StudentSolutionsPage: FC = () => { ? [] : homeworks.map(h => h.statsForTasks![taskIndexInHomework].taskId!) - const getTaskData = async (taskId: string, fullUpdate: boolean) => { - const task = await ApiSingleton.tasksApi.tasksGetTask(+taskId!) + const getTaskData = async (taskId: string, secondMentorId: string | undefined, fullUpdate: boolean) => { + const task = await ApiSingleton.tasksApi.tasksGetTask(+taskId!, true) if (!fullUpdate && versionsOfCurrentTask.includes(+taskId)) { setStudentSolutionsState({ @@ -171,14 +189,16 @@ const StudentSolutionsPage: FC = () => { const { taskSolutions, courseId, - statsForTasks - } = await ApiSingleton.solutionsApi.solutionsGetTaskSolutionsPageData(+taskId!) + statsForTasks, + courseMentors + } = await ApiSingleton.solutionsApi.solutionsGetTaskSolutionsPageData(+taskId!, secondMentorId) const studentSolutionsPreview = taskSolutions!.map(ts => ({ taskId: ts.taskId!, studentSolutionsPreview: ts.studentSolutions!.map(studentSolutions => { const ratedSolutionInfo = StudentStatsUtils.calculateLastRatedSolutionInfo(studentSolutions.solutions!, task.maxRating!) return { + hasDifferentReviewer: studentSolutions.hasDifferentReviewer!, student: studentSolutions.student!, ...ratedSolutionInfo, solutions: studentSolutions.solutions! } @@ -192,6 +212,7 @@ const StudentSolutionsPage: FC = () => { currentTaskId: taskId, homeworkSolutionsStats: statsForTasks!, taskStudentsSolutionsPreview: studentSolutionsPreview, + courseMentors: courseMentors!.filter(x => x.userId !== ApiSingleton.authService.getUserId()), courseId: courseId! }) } @@ -202,13 +223,14 @@ const StudentSolutionsPage: FC = () => { }, [courseId]) useEffect(() => { - getTaskData(taskId!, false) + getTaskData(taskId!, secondMentorId, false) }, [taskId]) useEffect(() => { setCurrentStudentId(studentId!) }, [studentId]) + const courseStudents = currentTaskSolutions.map(x => x.student) const currentStudent = currentTaskSolutions.find(x => x.student.userId === currentStudentId) const renderUnratedSolutionsCountChip = (t: TaskSolutionsStats, isSelected: boolean) => { @@ -218,29 +240,41 @@ const StudentSolutionsPage: FC = () => { : } - const renderStudentListItem = (student: StudentDataDto) => { - if (!student.characteristics || student.characteristics.tags?.length === 0) return student.surname + " " + student.name - const tags = student.characteristics.tags! + const renderStudentListItem = (student: StudentDataDto, hasDifferentReviewer: boolean) => { + const tags = student.characteristics?.tags || [] const hasGoodCharacteristics = tags.some(x => x.startsWith("+")) const hasBadCharacteristics = tags.some(x => x.startsWith("-")) - if (!hasGoodCharacteristics && !hasBadCharacteristics) return student.surname + " " + student.name + const studentFio = tags.some(x => x === RemovedFromCourseTag) + ? {student.surname + " " + student.name} + : student.surname + " " + student.name - return
{student.surname + " " + student.name} + return
{studentFio} {hasGoodCharacteristics && } {hasBadCharacteristics && } + {hasDifferentReviewer && secondMentor && + {secondMentor.name} {secondMentor.surname} + }
} + const {courseFilesState} = FilesUploadWaiter(courseId, CourseUnitType.Solution, false); + if (isLoaded) { return (
- {taskSolutionsStats!.map((t, index) => { const isCurrent = versionsOfCurrentTask.includes(t.taskId!) @@ -274,6 +308,23 @@ const StudentSolutionsPage: FC = () => { + {courseMentors.length > 0 && option.name! + ' ' + option.surname!} + value={secondMentor} + onChange={async (_, newValue) => { + setSecondMentorId(newValue?.userId) + await getTaskData(currentTaskId, newValue?.userId, true) + }} + renderInput={params => } + />} { color, solutionsDescription, lastRatedSolution, - student + student, + hasDifferentReviewer }, idx) => { const {userId} = student const storageKey = { @@ -325,7 +377,9 @@ const StudentSolutionsPage: FC = () => { size={"small"} label={lastRatedSolution == undefined ? "?" : lastRatedSolution.rating}/> } - + @@ -336,6 +390,7 @@ const StudentSolutionsPage: FC = () => { {currentHomeworksGroup && taskIndexInHomework !== -1 && currentHomeworksGroup.statsForHomeworks!.length > 1 && navigate(`/task/${currentHomeworksGroup!.statsForHomeworks![value].statsForTasks![taskIndexInHomework]!.taskId!}/${currentStudentId}`)} + defaultValue={currentHomeworksGroup!.statsForHomeworks!.length - 1} variant="scrollable" scrollButtons={"auto"} value={versionOfTask} @@ -358,18 +413,21 @@ const StudentSolutionsPage: FC = () => { isExpanded={false} showForCourse={false} /> - {currentStudent && { //const nextStudentIndex = studentSolutionsPreview.findIndex(x => x.student.userId !== currentStudentId && x.lastSolution && x.lastSolution.state === Solution.StateEnum.NUMBER_0) - await getTaskData(currentTaskId, true) + await getTaskData(currentTaskId, secondMentorId, true) //else navigate(`/task/${currentTaskId}/${studentSolutionsPreview[nextStudentIndex].student.userId}`) }} - />} + courseFiles={courseFilesState.courseFiles} + processingFiles={courseFilesState.processingFilesState} + />
diff --git a/hwproj.front/src/components/Solutions/TaskSolutionComponent.tsx b/hwproj.front/src/components/Solutions/TaskSolutionComponent.tsx index 5cec18e92..5d3e424e8 100644 --- a/hwproj.front/src/components/Solutions/TaskSolutionComponent.tsx +++ b/hwproj.front/src/components/Solutions/TaskSolutionComponent.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import {FC, useEffect, useState} from 'react'; import {Button, CircularProgress, Grid, TextField, Typography} from "@material-ui/core"; +import CheckCircleOutlineIcon from "@material-ui/icons/CheckCircleOutline"; import Link from '@material-ui/core/Link' import './style.css' import { @@ -8,10 +9,22 @@ import { HomeworkTaskViewModel, SolutionState, SolutionActualityDto, - SolutionActualityPart, StudentDataDto -} from '../../api' + SolutionActualityPart, StudentDataDto, FileInfoDTO +} from '@/api' import ApiSingleton from "../../api/ApiSingleton"; -import {Alert, Avatar, Rating, Stack, Tooltip, Card, CardContent, CardActions, IconButton, Chip} from "@mui/material"; +import { + Alert, + Avatar, + Rating, + Stack, + Tooltip, + Card, + CardContent, + CardActions, + IconButton, + Chip, + Box +} from "@mui/material"; import AvatarUtils from "../Utils/AvatarUtils"; import Utils from "../../services/Utils"; import {RatingStorage} from "../Storages/RatingStorage"; @@ -24,16 +37,37 @@ import CloseIcon from '@mui/icons-material/Close'; import {useSnackbar} from 'notistack'; import StudentStatsUtils from "../../services/StudentStatsUtils"; import {StudentCharacteristics} from "@/components/Students/StudentCharacteristics"; +import KeyboardCommandKeyIcon from '@mui/icons-material/KeyboardCommandKey'; +import MouseOutlinedIcon from '@mui/icons-material/MouseOutlined'; +import BlurOnIcon from '@mui/icons-material/BlurOn'; +import BlurOffIcon from '@mui/icons-material/BlurOff'; +import FileInfoConverter from "@/components/Utils/FileInfoConverter"; +import {IFileInfo} from "@/components/Files/IFileInfo"; +import FilesPreviewList from "@/components/Files/FilesPreviewList"; +import {CourseUnitType} from "@/components/Files/CourseUnitType"; +import {UserAvatar} from "@/components/Common/UserAvatar"; + +type TaskWithCriteria = HomeworkTaskViewModel & {}; + +type CriterionRating = { + criterionId: number; + name: string; + maxPoints: number; + value: number; + comment: string; +}; interface ISolutionProps { courseId: number, solution: GetSolutionModel | undefined, student: StudentDataDto, - task: HomeworkTaskViewModel, + task: TaskWithCriteria, forMentor: boolean, lastRating?: number, onRateSolutionClick?: () => void, isLastSolution: boolean, + courseFilesInfo: FileInfoDTO[], + isProcessing: boolean, } interface ISolutionState { @@ -45,18 +79,84 @@ interface ISolutionState { const TaskSolutionComponent: FC = (props) => { const storageKey = {taskId: props.task.id!, studentId: props.student.userId!, solutionId: props.solution?.id} + const criteriaDraftKey = + `criteria-draft:${props.task.id}:${props.student.userId}:${props.solution?.id ?? "new"}`; + + type CriteriaDraft = { + criteria: { criterionId: number; value: number | null }[]; + extraScore: number; + }; + + const loadCriteriaDraft = (): CriteriaDraft | null => { + if (typeof window === "undefined") return null; + try { + const raw = localStorage.getItem(criteriaDraftKey); + if (!raw) return null; + return JSON.parse(raw) as CriteriaDraft; + } catch { + return null; + } + }; + + const saveCriteriaDraft = (draft: CriteriaDraft) => { + if (typeof window === "undefined") return; + try { + localStorage.setItem(criteriaDraftKey, JSON.stringify(draft)); + } catch { /* empty */ + } + }; + + const clearCriteriaDraft = () => { + if (typeof window === "undefined") return; + try { + localStorage.removeItem(criteriaDraftKey); + } catch { + } + }; const getDefaultState = (): ISolutionState => { - const storageValue = RatingStorage.tryGet(storageKey) - return ({ + const storageValue = RatingStorage.tryGet(storageKey); + + const clickedForRate = props.forMentor + ? (storageValue !== null) + : false; + + return { points: storageValue?.points || props.solution?.rating || 0, lecturerComment: storageValue?.comment || props.solution?.lecturerComment || "", - clickedForRate: storageValue !== null, - addBonusPoints: false - }); - } + clickedForRate, + addBonusPoints: hasCriteria, + }; + }; + + + const taskWithCriteria = props.task as TaskWithCriteria; + const hasCriteria = !!(taskWithCriteria.criteria && taskWithCriteria.criteria.length); + const [state, setState] = useState(getDefaultState); + + const initialDraft = loadCriteriaDraft(); - const [state, setState] = useState(getDefaultState) + const [criterionRatings, setCriterionRatings] = useState(() => + (taskWithCriteria.criteria ?? []).map(c => { + const id = c.id!; + const draftValue = initialDraft?.criteria + ?.find(x => x.criterionId === id)?.value; + + return { + criterionId: id, + name: c.name ?? "", + maxPoints: c.maxPoints ?? 0, + value: draftValue || NaN, + comment: "", + }; + }) + ); + + const [extraScore, setExtraScore] = useState( + initialDraft?.extraScore ?? 0 + ); + const [criteriaModified, setCriteriaModified] = useState(false); + const [showOriginalCommentText, setShowOriginalCommentText] = useState(false) const [achievement, setAchievementState] = useState(undefined) const [rateInProgress, setRateInProgressState] = useState(false) const [solutionActuality, setSolutionActuality] = useState(undefined) @@ -64,22 +164,116 @@ const TaskSolutionComponent: FC = (props) => { const {enqueueSnackbar} = useSnackbar() useEffect(() => { - setState(getDefaultState()) - getAchievementState() - setRateInProgressState(false) - getActuality() - }, [props.student.userId, props.task.id, props.solution?.id, props.solution?.rating]) + setState(getDefaultState()); + + const draft = loadCriteriaDraft(); + + setCriterionRatings( + (taskWithCriteria.criteria ?? []).map(c => { + const id = c.id ?? 0; + const draftValue = draft?.criteria + ?.find(x => x.criterionId === id)?.value; + + return { + criterionId: id, + name: c.name ?? "", + maxPoints: c.maxPoints ?? 0, + value: draftValue || NaN, + comment: "", + }; + }) + ); + + setExtraScore(draft?.extraScore ?? 0); + setCriteriaModified(false); + getAchievementState(); + setRateInProgressState(false); + getActuality(); + setShowOriginalCommentText(false); + }, [props.student.userId, props.task.id, props.solution?.id, props.solution?.rating]); useEffect(() => { - if (!state.clickedForRate) return - RatingStorage.set(storageKey, {points: state.points, comment: state.lecturerComment}) - }, [state.points, state.lecturerComment]) + if (!hasCriteria || !state.addBonusPoints || !state.clickedForRate || !criteriaModified) return; + + const criteriaTotal = criterionRatings.reduce( + (sum, c) => sum + (Number.isFinite(c.value) ? Number(c.value) : 0), + 0 + ); + const total = criteriaTotal + (Number.isFinite(extraScore) ? extraScore : 0); + + setState(prev => ({...prev, points: total})); + }, [criterionRatings, extraScore, hasCriteria, state.addBonusPoints, state.clickedForRate, criteriaModified]); + + const criteriaSum = + criterionRatings.reduce( + (sum, c) => sum + (Number.isFinite(c.value) ? Number(c.value) : 0), + 0 + ) + (Number.isFinite(extraScore) ? extraScore : 0); + + const isRateButtonDisabled = hasCriteria && criteriaSum < 0; + + const [isCtrlPressed, setIsCtrlPressed] = useState(false) useEffect(() => { - if (state.clickedForRate) return - RatingStorage.clean(storageKey) + if (!props.forMentor) return + + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === "Control") { + setIsCtrlPressed(true); + } + } + + const handleKeyUp = (event: KeyboardEvent) => { + if (event.key === "Control") { + setIsCtrlPressed(false); + } + } + + window.addEventListener("keydown", handleKeyDown); + window.addEventListener("keyup", handleKeyUp); + + return () => { + if (!props.forMentor) return + window.removeEventListener("keydown", handleKeyDown); + window.removeEventListener("keyup", handleKeyUp); + } + }, []) + + + useEffect(() => { + if (!state.clickedForRate) return; + + RatingStorage.set(storageKey, { + points: state.points, + comment: state.lecturerComment + }); + + const draft: CriteriaDraft = { + criteria: criterionRatings.map(cr => ({ + criterionId: cr.criterionId, + value: Number.isFinite(cr.value) ? cr.value : null, + })), + extraScore: Number.isFinite(extraScore) ? extraScore : 0, + }; + + saveCriteriaDraft(draft); + }, [ + state.points, + state.lecturerComment, + criterionRatings, + extraScore, + state.clickedForRate, + ]); + + + useEffect(() => { + if (state.clickedForRate) return; + + RatingStorage.clean(storageKey); + clearCriteriaDraft(); }, [state.clickedForRate]); + const checkTestsActuality = props.solution && props.isLastSolution && props.solution.githubUrl && @@ -111,31 +305,68 @@ const TaskSolutionComponent: FC = (props) => { } } - const rateSolution = async () => { - setRateInProgressState(true) - if (props.solution) { - await ApiSingleton.solutionsApi.solutionsRateSolution( - props.solution.id!, - { - rating: points, - lecturerComment: lecturerComment - } - ) - } else await ApiSingleton.solutionsApi.solutionsPostEmptySolutionWithRate( - props.task.id!, - { - comment: "", - githubUrl: "", - lecturerComment: state.lecturerComment, - publicationDate: undefined, - rating: state.points, - studentId: props.student.userId + const buildCommentWithCriteria = (baseComment: string): string => { + if (!hasCriteria || criterionRatings.length === 0) return baseComment; + + const rows: string[] = criterionRatings.map(cr => { + const safeValue = Number.isFinite(cr.value) ? cr.value : 0; + return `| ${cr.name} | ${safeValue} / ${cr.maxPoints} |`; + }); + + if ((extraScore ?? 0) !== 0) { + rows.push(`| Доп. оценка | ${extraScore} |`); + } + + const table = [ + "| Критерий оценивания | Баллы |", + "| --- | --- |", + ...rows, + ].join("\n"); + + const trimmed = (baseComment ?? "").trim(); + const prefix = trimmed ? trimmed + "\n\n" : ""; + + return `${prefix}${table}`; + }; + + const rateSolution = async (points: number, lecturerComment: string) => { + setRateInProgressState(true); + + try { + const finalComment = buildCommentWithCriteria(lecturerComment); + + if (props.solution) { + await ApiSingleton.solutionsApi.solutionsRateSolution( + props.solution.id!, + { + rating: points, + lecturerComment: finalComment, + } + ); + } else { + await ApiSingleton.solutionsApi.solutionsPostEmptySolutionWithRate( + props.task.id!, + { + comment: "", + githubUrl: "", + lecturerComment: finalComment, + publicationDate: undefined, + rating: points, + studentId: props.student.userId, + } + ); } - ) - setState(prevState => ({...prevState, clickedForRate: false})) - enqueueSnackbar('Решение успешно оценено', {variant: "success", autoHideDuration: 1700}); - props.onRateSolutionClick?.() - } + + setState(prevState => ({...prevState, clickedForRate: false})); + enqueueSnackbar("Решение успешно оценено", { + variant: "success", + autoHideDuration: 1700, + }); + props.onRateSolutionClick?.(); + } finally { + setRateInProgressState(false); + } + }; const {solution, lastRating, student, task} = props const maxRating = task.maxRating! @@ -148,10 +379,16 @@ const TaskSolutionComponent: FC = (props) => { const lecturer = solution?.lecturer const lecturerName = lecturer && (lecturer.surname + " " + lecturer.name) const commitsActuality = solutionActuality?.commitsActuality + const filesInfo = solution?.id ? FileInfoConverter.getCourseUnitFilesInfo(props.courseFilesInfo, CourseUnitType.Solution, solution.id) : [] const getDatesDiff = (_date1: Date, _date2: Date) => { - const date1 = new Date(_date1).getTime() - const date2 = new Date(_date2).getTime() + const truncateToMinutes = (date: Date) => { + date.setSeconds(0, 0) // Убираем секунды и миллисекунды + return date + } + + const date1 = truncateToMinutes(new Date(_date1)).getTime() + const date2 = truncateToMinutes(new Date(_date2)).getTime() const diffTime = date1 - date2 if (diffTime <= 0) return "" return Utils.pluralizeDateTime(diffTime); @@ -168,159 +405,525 @@ const TaskSolutionComponent: FC = (props) => { title={
{status.comment}
}>{icon} } + const clickForRate = async (points: number, clickedForRate: boolean) => { + setState((prevState) => ({ + ...prevState, + points: points, + clickedForRate: clickedForRate && !isCtrlPressed + })) + if (isCtrlPressed) await rateSolution(points, lecturerComment) + } + const renderRateInput = () => { - const showThumbs = maxRating === 1 - const isEditable = props.forMentor && (!isRated || state.clickedForRate) - const thumbsHandler = (rating: number) => { - setState((prevState) => ({ - ...prevState, - points: rating, - clickedForRate: isEditable - })) + const showThumbs = maxRating === 1; + const isEditable = props.forMentor && (!isRated || state.clickedForRate); + + if (hasCriteria && props.forMentor) { + if (!isRated) { + return ( + + ); + } } + + const thumbsHandler = (rating: number) => { + clickForRate(rating, isEditable); + }; + if (maxRating <= 10 && points <= maxRating && !addBonusPoints) - return ( - {showThumbs && < - Stack direction={"row"} alignItems={"center"}> - thumbsHandler(1)}> - - - thumbsHandler(0)}> - - - - } - {!showThumbs && - { - setState((prevState) => ({ - ...prevState, - points: newValue || 0, - addBonusPoints: points > maxRating, - clickedForRate: true - })) - }} - /> - } - {!showThumbs && - {points + " / " + maxRating} - } - {!addBonusPoints && props.forMentor && state.clickedForRate && - - - setState(prevState => ({...prevState, addBonusPoints: true}))}> - Нужна особая оценка? - - - - } - ) - return ( - - {isEditable - ? { - e.persist() - setState((prevState) => ({ - ...prevState, - points: +e.target.value - })) - }} - onClick={() => { - if (isRated) return - setState((prevState) => ({ - ...prevState, - clickedForRate: props.forMentor - })); - }} - /> - : {points}} size={"medium"}/>} + return ( + + {showThumbs && ( + + + thumbsHandler(1)}> + + + thumbsHandler(0)}> + + + + + )} + + {!showThumbs && ( + + + {(isEditable || !isRated) && ( + thumbsHandler(0)} + > + + + )} + { + const isFirefox = navigator.userAgent + .toLowerCase() + .includes("firefox"); + if (event.ctrlKey && isFirefox) { + const ratingElement = event.currentTarget; + const {left, width} = ratingElement.getBoundingClientRect(); + const relativeX = (event.clientX - left) / width; + const star = Math.ceil(relativeX * maxRating) || 0; + const rating = star === points ? 0 : star; + + clickForRate(rating || 0, true); + } + }} + onChange={(_, newValue) => { + clickForRate(newValue || 0, true); + }} + /> + + + )} + + {!addBonusPoints && props.forMentor && state.clickedForRate && ( + + + + + setState(prev => ({...prev, addBonusPoints: true})) + } + > + Нужна особая оценка? + + + + + )} + + ); + + return ( + + + {isEditable ? ( + { + if (hasCriteria) return; + + e.persist(); + setState(prevState => ({ + ...prevState, + points: +e.target.value, + })); + }} + onClick={() => { + if (isRated) return; + setState(prevState => ({ + ...prevState, + clickedForRate: props.forMentor, + })); + }} + /> + ) : ( + {points}} + size="medium" + /> + )} + + {` / ${maxRating}`} - - {" / " + maxRating} + ); + }; + + + const renderCriteriaBlock = () => { + if (!hasCriteria) return null; + + const criteriaTotal = criterionRatings.reduce( + (sum, c) => sum + (Number.isFinite(c.value) ? Number(c.value) : 0), + 0 + ); + const totalWithExtra = criteriaTotal + (Number.isFinite(extraScore) ? extraScore : 0); + const isCriteriaSumNegative = totalWithExtra < 0; + + return ( + + + + {taskWithCriteria.criteria!.map((c, index) => { + const existingRating = criterionRatings.find(r => r.criterionId === c.id); + + const current = + existingRating || { + criterionId: c.id, + name: c.name, + maxPoints: c.maxPoints, + value: Number.NaN, + comment: "", + }; + + const numericValue = Number.isFinite(current.value) ? current.value : 0; + + const hasExplicitValue = Number.isFinite(current.value); + + const isThumbCriterion = c.maxPoints === 1; + const hasStars = + typeof c.maxPoints === "number" && c.maxPoints <= 10 && !isThumbCriterion; + + const isFilled = hasExplicitValue && (isThumbCriterion || numericValue !== 0); + + return ( + + + + + + + + {c.name} + + + + + + {isThumbCriterion ? ( + + { + setCriteriaModified(true); + setCriterionRatings(prev => + prev.map(r => + r.criterionId === c.id + ? {...r, value: 1} + : r + ) + ); + }} + > + + + + { + setCriteriaModified(true); + setCriterionRatings(prev => + prev.map(r => + r.criterionId === c.id + ? {...r, value: 0} + : r + ) + ); + }} + > + + + + + ) : hasStars ? ( + { + let val = Number(newValue || 0); + if (Number.isNaN(val)) val = 0; + if (c.maxPoints && val > c.maxPoints) { + val = c.maxPoints; + } + + setCriteriaModified(true); + setCriterionRatings(prev => + prev.map(r => + r.criterionId === c.id + ? {...r, value: val} + : r + ) + ); + }} + /> + ) : ( + + { + let val = Number(e.target.value); + if (Number.isNaN(val)) val = 0; + + setCriteriaModified(true); + setCriterionRatings(prev => + prev.map(r => + r.criterionId === c.id + ? {...r, value: val} + : r + ) + ); + }} + /> + + + / {c.maxPoints} + + + )} + + + ); + })} + + + + + + + Доп. оценка (опционально) + + + { + let val = Number(e.target.value || 0); + if (Number.isNaN(val)) val = 0; + + setCriteriaModified(true); + setExtraScore(val); + }} + /> + + + + + + {`Сумма по критериям: ${totalWithExtra} из ${maxRating}`} + + + - ) - } + ); + }; + const sentAfterDeadline = solution && task.hasDeadline && getDatesDiff(solution.publicationDate!, task.deadlineDate!) const renderRatingCard = () => { const rating = points * 100 / maxRating const {backgroundColor, color} = - state.clickedForRate || !isRated ? {backgroundColor: undefined, color: undefined} + state.clickedForRate || !isRated + ? {backgroundColor: undefined, color: undefined} : rating >= 70 ? {backgroundColor: "rgb(237,247,237)", color: "rgb(30,70,32)"} : rating <= 34 ? {backgroundColor: "rgb(253,237,237)", color: "rgb(95,33,32)"} : {backgroundColor: "rgb(255,244,229)", color: "rgb(102,60,0)"} - return + + const isNegative = points < 0 + return - + {(!hasCriteria || !state.clickedForRate) && {renderRateInput()} - + } + {props.forMentor && hasCriteria && state.addBonusPoints && state.clickedForRate && ( + + {renderCriteriaBlock()} + + )} + + {!isRated && !state.clickedForRate && maxRating <= 10 && !addBonusPoints && + + Нажмите{" "} + + + Ctrl + {" "} + {" "} + + ЛКМ + + {" "}для быстрого оценивания + + } {lastRating !== undefined && state.clickedForRate && Оценка за предыдущее решение: {lastRating} ⭐ } - {lecturerName && isRated && + {lecturerName && isRated && ( - {state.clickedForRate ? : - } + {props.forMentor && state.clickedForRate ? ( + + + + ) : ( + + )} + - {state.clickedForRate ? "..." : -
{lecturerName} + {props.forMentor && state.clickedForRate ? ( + "..." + ) : ( +
+ {lecturerName} {lecturer!.companyName} -
} +
+ )}
- {ratingTime && - {ratingTime} - } + {ratingTime && ( + + {ratingTime} + + )}
-
} - {state.clickedForRate - ? - { - setState((prevState) => ({ - ...prevState, - lecturerComment: value - })) - }} - /> - : isRated && + )} + {state.clickedForRate && props.forMentor + ? ( + + { + setState((prevState) => ({ + ...prevState, + lecturerComment: value, + })); + }} + /> + + ) + : isRated && ( = (props) => { textColor={color} /> + ) }
- {props.forMentor && state.clickedForRate && - } - style={{color: "#3f51b5"}} - loading={rateInProgress} - loadingPosition="end" - size="small" - onClick={rateSolution} - > - {isRated ? "Изменить оценку" : "Оценить решение"} - - {!rateInProgress && - } - } + {props.forMentor && state.clickedForRate && ( + <> + + } + style={isRateButtonDisabled ? {} : {color: "#3f51b5"}} + loading={rateInProgress} + loadingPosition="end" + size="small" + disabled={isRateButtonDisabled || rateInProgress} + onClick={() => { + rateSolution(points, lecturerComment); + }} + > + {isRated ? "Изменить оценку" : "Оценить решение"} + + + {!rateInProgress && ( + + )} + + + )} {props.forMentor && isRated && !state.clickedForRate && } @@ -393,13 +1027,13 @@ const TaskSolutionComponent: FC = (props) => { alignItems={students.length === 1 ? "center" : "normal"} spacing={1}> {students && students.map(t => - + )} {solution.githubUrl && @@ -409,17 +1043,53 @@ const TaskSolutionComponent: FC = (props) => { ? renderTestsStatus(solutionActuality.testsActuality) : )} - - {postedSolutionTime} - + + + {postedSolutionTime} {solution.isModified && "(отредактировано)"} + + {solution?.comment && + + {showOriginalCommentText ? "Показать отформатированный текст решения" : "Показать оригинальный текст решения"} +
}> +
setShowOriginalCommentText(!showOriginalCommentText)}> + {showOriginalCommentText + ? + : } +
+ } +
+ {solution.comment && - - + + {showOriginalCommentText + ? {solution.comment} + : } } + {props.isProcessing ? ( +
+ +   Обрабатываем файлы... +
+ ) : filesInfo.length > 0 && ( +
+ { + const url = await ApiSingleton.customFilesApi.getDownloadFileLink(fileInfo.id!) + window.open(url, '_blank'); + }} + /> +
+ )} +
} {props.forMentor && props.isLastSolution && student && @@ -436,13 +1106,6 @@ const TaskSolutionComponent: FC = (props) => { } - { - points > maxRating && - - Решение оценено выше максимального балла. - - - } { checkAchievement && = (props) => { { (props.forMentor || isRated) && - {renderRatingCard()} + { + renderRatingCard() + } + } } diff --git a/hwproj.front/src/components/Solutions/TaskSolutions.tsx b/hwproj.front/src/components/Solutions/TaskSolutions.tsx index 49db89ecf..76220a182 100644 --- a/hwproj.front/src/components/Solutions/TaskSolutions.tsx +++ b/hwproj.front/src/components/Solutions/TaskSolutions.tsx @@ -2,11 +2,12 @@ import * as React from 'react'; import {FC, useEffect, useState} from 'react'; import TaskSolutionComponent from "./TaskSolutionComponent"; import { + FileInfoDTO, GetSolutionModel, GetTaskQuestionDto, HomeworkTaskViewModel, SolutionState, StudentDataDto -} from '../../api'; +} from '@/api'; import {Grid, Tab, Tabs} from "@material-ui/core"; import {Chip, Divider, Stack, Tooltip, Badge} from "@mui/material"; import Utils from "../../services/Utils"; @@ -17,12 +18,19 @@ import ApiSingleton from "../../api/ApiSingleton"; import {DotLottieReact} from '@lottiefiles/dotlottie-react'; interface ITaskSolutionsProps { - courseId: number, + courseId: number task: HomeworkTaskViewModel solutions: GetSolutionModel[] - student: StudentDataDto + student: StudentDataDto | undefined + courseStudents: StudentDataDto[] forMentor: boolean onSolutionRateClick?: () => void + courseFiles: FileInfoDTO[] + processingFiles: { + [solutionId: number]: { + isLoading: boolean; + } + }; } interface ITaskSolutionsState { @@ -46,8 +54,8 @@ const TaskSolutions: FC = (props) => { } useEffect(() => { - setState({tabValue: 1}) - }, [props.student.userId, props.task.id]) + setState({tabValue: props.student == null ? 0 : 1}) + }, [props.student?.userId, props.task.id]) useEffect(() => { getQuestions() @@ -55,8 +63,13 @@ const TaskSolutions: FC = (props) => { const {tabValue} = state const {solutions, student, forMentor, task} = props - const lastSolution = solutions[solutions.length - 1] - const arrayOfRatedSolutions = solutions.slice(0, solutions.length - 1) + const sortedSolutions = [...solutions].sort((a, b) => { + const da = new Date(a.ratingDate || a.publicationDate!).getTime(); + const db = new Date(b.ratingDate || b.publicationDate!).getTime(); + return da - db; + }); + const lastSolution = sortedSolutions[sortedSolutions.length - 1] + const arrayOfRatedSolutions = sortedSolutions.slice(0, solutions.length - 1) const previousSolution = arrayOfRatedSolutions && arrayOfRatedSolutions[arrayOfRatedSolutions.length - 1] const lastRating = previousSolution && previousSolution.state !== SolutionState.NUMBER_0 // != Posted ? previousSolution.rating @@ -65,7 +78,7 @@ const TaskSolutions: FC = (props) => { const newQuestions = questionsState.filter(x => x.answer === null).length const renderSolutionsRate = () => { - const ratedSolutions = solutions + const ratedSolutions = sortedSolutions .filter(x => x.state !== SolutionState.NUMBER_0) .map(x => ({ publicationTime: new Date(x.publicationDate!), @@ -160,26 +173,35 @@ const TaskSolutions: FC = (props) => { color={newQuestions === 0 ? "success" : "primary"}> }/> - - {arrayOfRatedSolutions.length > 0 && } + {student !== undefined && } + {arrayOfRatedSolutions.length > 0 && +
Предыдущие попытки
+ + }/>} {tabValue === 0 && } {tabValue === 1 && - {lastSolution || forMentor + {(lastSolution || forMentor) && student !== undefined ? + courseId={props.courseId} + courseFilesInfo={props.courseFiles} + isProcessing={lastSolution && (props.processingFiles[lastSolution.id!]?.isLoading || false)} + /> :
Студент не отправил ни одного решения. = (props) => { student={student!} onRateSolutionClick={onSolutionRateClick} isLastSolution={false} - courseId={props.courseId}/> + courseId={props.courseId} + courseFilesInfo={props.courseFiles} + isProcessing={props.processingFiles[x.id!]?.isLoading || false} + /> {i < arrayOfRatedSolutions.length - 1 ? : null} )} diff --git a/hwproj.front/src/components/Solutions/TaskSolutionsPage.tsx b/hwproj.front/src/components/Solutions/TaskSolutionsPage.tsx index fa3c1b42b..865ebe999 100644 --- a/hwproj.front/src/components/Solutions/TaskSolutionsPage.tsx +++ b/hwproj.front/src/components/Solutions/TaskSolutionsPage.tsx @@ -1,27 +1,15 @@ import * as React from "react"; +import {FC, useEffect, useState} from "react"; import Task from "../Tasks/Task"; import Typography from "@material-ui/core/Typography"; import AddOrEditSolution from "./AddOrEditSolution"; import Button from "@material-ui/core/Button"; import TaskSolutions from "./TaskSolutions"; -import { - AccountDataDto, - HomeworksGroupUserTaskSolutions, - HomeworkTaskViewModel, - Solution, - SolutionState -} from "../../api/"; +import {AccountDataDto, HomeworksGroupUserTaskSolutions, HomeworkTaskViewModel, Solution, SolutionState} from "@/api"; import ApiSingleton from "../../api/ApiSingleton"; -import {FC, useEffect, useState} from "react"; import {Grid, Tab, Tabs} from "@material-ui/core"; -import { - Checkbox, - Chip, - SelectChangeEvent, - Stack, - Tooltip -} from "@mui/material"; -import {useParams, Link, useNavigate} from "react-router-dom"; +import {Checkbox, Chip, SelectChangeEvent, Stack, Tooltip} from "@mui/material"; +import {Link, useNavigate, useParams} from "react-router-dom"; import Step from "@mui/material/Step"; import StepButton from "@mui/material/StepButton"; import StudentStatsUtils from "../../services/StudentStatsUtils"; @@ -29,6 +17,8 @@ import {getTip} from "../Common/HomeworkTags"; import Lodash from "lodash"; import {appBarStateManager} from "../AppBar"; import {DotLottieReact} from "@lottiefiles/dotlottie-react"; +import {FilesUploadWaiter} from "@/components/Files/FilesUploadWaiter"; +import {CourseUnitType} from "@/components/Files/CourseUnitType"; interface ITaskSolutionsState { isLoaded: boolean @@ -138,6 +128,11 @@ const TaskSolutionsPage: FC = () => { }); }) + const { + courseFilesState, + updateCourseUnitFiles, + } = FilesUploadWaiter(courseId, CourseUnitType.Solution, false); + const currentHomeworksGroup = taskSolutionsWithPreview .find(x => x.homeworkSolutions! .some(h => h.previews! @@ -280,20 +275,28 @@ const TaskSolutionsPage: FC = () => { task={task} forMentor={false} student={student} - solutions={currentTaskSolutions}/> + courseStudents={[student]} + solutions={currentTaskSolutions} + courseFiles={courseFilesState.courseFiles} + processingFiles={courseFilesState.processingFilesState} + /> )} {taskSolutionPage.addSolution && } + supportsGroup={task.isGroupWork!} + courseFilesInfo={courseFilesState.courseFiles} + onStartProcessing={updateCourseUnitFiles} + />}
: (
diff --git a/hwproj.front/src/components/Solutions/UnratedSolutionsAndOpenQuestions.tsx b/hwproj.front/src/components/Solutions/UnratedSolutionsAndOpenQuestions.tsx new file mode 100644 index 000000000..99214464e --- /dev/null +++ b/hwproj.front/src/components/Solutions/UnratedSolutionsAndOpenQuestions.tsx @@ -0,0 +1,308 @@ +import {AccountDataDto, QuestionsSummary, SolutionPreviewView, UnratedSolutionPreviews} from "@/api"; +import * as React from "react"; +import {NavLink} from "react-router-dom"; +import { + Divider, + Grid, + ListItem, + Typography, + Chip, Card, CardContent, Autocomplete, Stack, + Badge +} from "@mui/material"; +import {FC, useEffect, useState} from "react"; +import Utils from "../../services/Utils"; +import {RatingStorage} from "../Storages/RatingStorage"; +import TextField from "@mui/material/TextField"; +import ApiSingleton from "@/api/ApiSingleton"; +import {TestTip} from "@/components/Common/HomeworkTags"; + +interface IUnratedSolutionsProps { + unratedSolutionsPreviews: UnratedSolutionPreviews +} + +interface IFiltersState { + coursesFilter: string, + homeworksFilter: string, + tasksFilter: string, + studentsFilter: string + courses: string[], + homeworks: string[], + tasks: string[], + students: string[] +} + +const solutionPlurals = ["решение", "решения", "решений"] +const taskPlurals = ["задача содержит", "задачи содержат", "задач содержат"] + +type FilterTitleName = "coursesFilter" | "homeworksFilter" | "tasksFilter" | "studentsFilter" + +const UnratedSolutionsAndOpenQuestions: FC = (props) => { + const [openQuestions, setOpenQuestions] = useState([]) + useEffect(() => { + ApiSingleton.tasksApi.tasksGetOpenQuestions().then(res => setOpenQuestions(res)) + }, []); + + const unratedSolutions = props.unratedSolutionsPreviews.unratedSolutions! + const semiRatedSolutions = unratedSolutions.filter(x => RatingStorage.tryGet({ + solutionId: x.solutionId, + taskId: x.taskId!, + studentId: x.student!.userId! + }) != null) + const renderStudent = (s: AccountDataDto) => `${s.surname} ${s.name}` + const prepareStrings = (arr: string[]) => [...new Set(arr)].sort() + const courses = new Set(unratedSolutions.map(s => s.courseTitle!)) + const homeworks = new Set(unratedSolutions.map(s => s.homeworkTitle!)) + const tasks = new Set(unratedSolutions.map(s => s.taskTitle!)) + const students = new Set(unratedSolutions.map(t => renderStudent(t.student!))) + const getFilterSetting = (key: FilterTitleName) => { + const filterValue = localStorage.getItem(key) + if (!filterValue) { + return "" + } + if (key === "coursesFilter" && !courses.has(filterValue)) { + localStorage.removeItem("homeworksFilter") + localStorage.removeItem("tasksFilter") + localStorage.removeItem("studentsFilter") + } else if (key === "homeworksFilter" && !homeworks.has(filterValue)) { + localStorage.removeItem("tasksFilter") + localStorage.removeItem("studentsFilter") + } else if (key === "tasksFilter" && !tasks.has(filterValue)) { + localStorage.removeItem("studentsFilter") + } else if (key === "studentsFilter" && !students.has(filterValue)) { + } else { + return filterValue + } + localStorage.removeItem(key) + return "" + } + + const coursesFilter = getFilterSetting("coursesFilter") + const homeworksFilter = getFilterSetting("homeworksFilter") + const tasksFilter = getFilterSetting("tasksFilter") + const studentsFilter = getFilterSetting("studentsFilter") + + const filteredHomeworks = coursesFilter === "" ? unratedSolutions : unratedSolutions.filter(t => t.courseTitle === coursesFilter) + const filteredTasks = homeworksFilter === "" ? filteredHomeworks : filteredHomeworks.filter(t => t.homeworkTitle === homeworksFilter) + const filteredStudents = tasksFilter === "" ? filteredTasks : filteredTasks.filter(t => t.taskTitle === tasksFilter) + + const [filtersState, setFiltersState] = useState({ + coursesFilter: coursesFilter, + homeworksFilter: homeworksFilter, + tasksFilter: tasksFilter, + studentsFilter: studentsFilter, + courses: [...courses].sort(), + homeworks: prepareStrings(filteredHomeworks.map(t => t.homeworkTitle!)), + tasks: prepareStrings(filteredTasks.map(t => t.taskTitle!)), + students: prepareStrings(filteredStudents.map(t => renderStudent(t.student!))) + }) + + const filteredUnratedSolutions = unratedSolutions + .filter(t => !filtersState.coursesFilter || t.courseTitle === filtersState.coursesFilter) + .filter(t => !filtersState.homeworksFilter || t.homeworkTitle === filtersState.homeworksFilter) + .filter(t => !filtersState.tasksFilter || t.taskTitle === filtersState.tasksFilter) + .filter(t => !filtersState.studentsFilter || renderStudent(t.student!) === filtersState.studentsFilter) + + const randomSolution = filteredUnratedSolutions.length > 1 + ? filteredUnratedSolutions[Math.floor(Math.random() * filteredUnratedSolutions.length)] + : undefined + + const handleFilterChange = (filterName: FilterTitleName, value: string) => { + let courseFilter = filtersState.coursesFilter + let homeworkFilter = filtersState.homeworksFilter + let taskFilter = filtersState.tasksFilter + let studentFilter = filtersState.studentsFilter + + if (filterName === "coursesFilter") { + courseFilter = value + homeworkFilter = "" + taskFilter = "" + studentFilter = "" + } else if (filterName === "homeworksFilter") { + homeworkFilter = value + taskFilter = "" + studentFilter = "" + } else if (filterName === "tasksFilter") { + taskFilter = value + studentFilter = "" + } else if (filterName === "studentsFilter") { + studentFilter = value + } + + const filteredHomeworks = courseFilter === "" ? unratedSolutions : unratedSolutions.filter(t => t.courseTitle === courseFilter) + const filteredTasks = homeworkFilter === "" ? filteredHomeworks : filteredHomeworks.filter(t => t.homeworkTitle === homeworkFilter) + const filteredStudents = taskFilter === "" ? filteredTasks : filteredTasks.filter(t => t.taskTitle === taskFilter) + localStorage.setItem("coursesFilter", courseFilter) + localStorage.setItem("homeworksFilter", homeworkFilter) + localStorage.setItem("tasksFilter", taskFilter) + localStorage.setItem("studentsFilter", studentFilter) + setFiltersState(prevState => ({ + ...prevState, + coursesFilter: courseFilter, + homeworksFilter: homeworkFilter, + tasksFilter: taskFilter, + studentsFilter: studentFilter, + homeworks: prepareStrings(filteredHomeworks.map(t => t.homeworkTitle!)), + tasks: prepareStrings(filteredTasks.map(t => t.taskTitle!)), + students: prepareStrings(filteredStudents.map(t => renderStudent(t.student!))) + })) + } + + const renderSelect = (name: string, filterName: FilterTitleName, value: string, options: string[]) => { + return ( } + key={name} + onChange={(_, newValue) => handleFilterChange(filterName, newValue || "")} + />) + } + + const renderFilter = () => { + return
+ + + {renderSelect("Курс", "coursesFilter", filtersState.coursesFilter, filtersState.courses)} + + + {renderSelect("Задание", "homeworksFilter", filtersState.homeworksFilter, filtersState.homeworks)} + + + {renderSelect("Задача", "tasksFilter", filtersState.tasksFilter, filtersState.tasks)} + + + {renderSelect("Студент", "studentsFilter", filtersState.studentsFilter, filtersState.students)} + + + + {filteredUnratedSolutions.length < unratedSolutions.length && + + {`${filteredUnratedSolutions.length} ${Utils.pluralizeHelper(solutionPlurals, filteredUnratedSolutions.length)} найдено по заданному фильтру`} + + } + {randomSolution && + + + проверить случайное решение + + + } + +
+ } + + const renderSolutions = (solutions: SolutionPreviewView[]) => { + return solutions.map((solution, i) => ( + + + + + + + {solution.student!.surname} {solution.student!.name} {" • "} {solution.taskTitle} + {solution.isTest && } + + + + {solution.isFirstTry && solution.sentAfterDeadline && + + } + {!solution.isFirstTry && + + } + {solution.groupId && + + } + {solution.isCourseCompleted && + + + } + + + + {solution.courseTitle + " • " + solution.homeworkTitle} + + {Utils.renderReadableDate(solution.publicationDate!)} + {i < solutions.length - 1 ? + : null} + + )) + } + + return ( +
+ {openQuestions.length > 0 && + + +
+ + {`${openQuestions.length} ${Utils.pluralizeHelper(taskPlurals, openQuestions.length)} вопросы от студентов`} + +
+
{openQuestions.sort((a, b) => b.count! - a.count!).map((taskQuestions, i) => ( + + + + + + + + + {taskQuestions.taskTitle} + + + + + + + + ))}
+
+
+ } + {semiRatedSolutions.length > 0 && + + +
+ + {`${semiRatedSolutions.length} ${Utils.pluralizeHelper(solutionPlurals, semiRatedSolutions.length)} с незаконченной проверкой`} + +
+
{renderSolutions(semiRatedSolutions)}
+
+
+ } + {renderFilter()} + {unratedSolutions.length === 0 ? +
+ Все решения проверены. +
: +
+ {renderSolutions(filteredUnratedSolutions)} +
+ } +
+ ) +} + +export default UnratedSolutionsAndOpenQuestions; diff --git a/hwproj.front/src/components/Students/StudentCharacteristics.tsx b/hwproj.front/src/components/Students/StudentCharacteristics.tsx index 9cd157fa0..27c558e6d 100644 --- a/hwproj.front/src/components/Students/StudentCharacteristics.tsx +++ b/hwproj.front/src/components/Students/StudentCharacteristics.tsx @@ -10,12 +10,13 @@ import { DialogContent, Autocomplete, DialogActions, - AlertTitle, Stack + AlertTitle, } from '@mui/material'; import {StudentCharacteristicsDto} from '@/api'; import TextField from "@material-ui/core/TextField"; import {MarkdownEditor, MarkdownPreview} from "@/components/Common/MarkdownEditor"; import ApiSingleton from "@/api/ApiSingleton"; +import {RemovedFromCourseTag} from "@/components/Common/StudentTags"; interface Props { @@ -144,15 +145,17 @@ const EditStudentCharacteristics: React.FC void, isOpe multiple freeSolo id="tags-outlined" - options={["+ Талантливый студент", "- Списывает", "Удален с курса"]} + options={["+ Талантливый студент", "- Списывает", RemovedFromCourseTag]} value={characteristics?.tags ?? []} defaultValue={characteristics?.tags ?? []} filterSelectedOptions onChange={(e, values) => { e.persist() + const formatted = values.map(t => t.trim().split(RegExp("\\s+")).join(" ")) + const filtered = formatted.filter(t => t.length > 0) setCharacteristics((prevState) => ({ ...prevState, - tags: values + tags: filtered, })) }} renderTags={(values, getTagProps) =>
diff --git a/hwproj.front/src/components/Tasks/CourseTaskExperimental.tsx b/hwproj.front/src/components/Tasks/CourseTaskExperimental.tsx index f7bc4287d..d1a4af133 100644 --- a/hwproj.front/src/components/Tasks/CourseTaskExperimental.tsx +++ b/hwproj.front/src/components/Tasks/CourseTaskExperimental.tsx @@ -1,16 +1,34 @@ -import {Alert, CardActions, CardContent, Chip, Divider, Grid, IconButton, TextField, Typography} from "@mui/material"; +import { + Alert, + CardActions, + CardContent, + Chip, + Divider, + Grid, + IconButton, + TextField, + Typography, + Button, + Box, + Link +} from "@mui/material"; import {MarkdownEditor, MarkdownPreview} from "components/Common/MarkdownEditor"; -import {FC, useEffect, useState} from "react" -import {ActionOptions, HomeworkTaskViewModel, HomeworkViewModel} from "../../api"; +import {FC, useEffect, useState, useMemo} from "react" +import {ActionOptions, CriterionViewModel, HomeworkTaskViewModel, HomeworkViewModel} from "@/api"; import ApiSingleton from "../../api/ApiSingleton"; import * as React from "react"; import EditIcon from "@mui/icons-material/Edit"; import DeleteIcon from "@mui/icons-material/Delete"; -import {Button} from "@material-ui/core"; import {LoadingButton} from "@mui/lab"; import TaskPublicationAndDeadlineDates from "../Common/TaskPublicationAndDeadlineDates"; import DeletionConfirmation from "../DeletionConfirmation"; import ActionOptionsUI from "../Common/ActionOptions"; +import {Stack} from "@mui/material"; +import CloseIcon from "@mui/icons-material/Close"; +import Collapse from "@mui/material/Collapse"; +import ExpandLessIcon from "@mui/icons-material/ExpandLess"; +import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; + interface IEditTaskMetadataState { hasDeadline: boolean | undefined; @@ -18,23 +36,80 @@ interface IEditTaskMetadataState { isDeadlineStrict: boolean | undefined; publicationDate: Date | undefined; isPublished: boolean; + hasErrors: boolean } +type TaskEditData = HomeworkTaskViewModel & { + isModified?: boolean; + hasErrors?: boolean; + suggestedMaxRating?: number; +}; + const CourseTaskEditor: FC<{ - speculativeTask: HomeworkTaskViewModel, + speculativeTask: TaskEditData, speculativeHomework: HomeworkViewModel, - onUpdate: (update: HomeworkTaskViewModel & { isDeleted?: boolean }) => void, + onUpdate: (update: { task: TaskEditData, isDeleted?: boolean, isSaved?: boolean }) => void, + getAllHomeworks: () => HomeworkViewModel[], toEditHomework: () => void, }> = (props) => { const [taskData, setTaskData] = useState<{ task: HomeworkTaskViewModel, homework: HomeworkViewModel, isLoaded: boolean - }>({task: props.speculativeTask, homework: props.speculativeHomework, isLoaded: false}) + }>({ + task: props.speculativeTask, + homework: props.speculativeHomework, + isLoaded: props.speculativeTask.id! < 0 || props.speculativeTask.isModified === true + }) + + const [criteria, setCriteria] = useState(taskData.task.criteria || []) + const [isCriteriaOpen, setIsCriteriaOpen] = useState(false) + + const addDefaultCriterion = () => { + setCriteria(prev => [ + ...prev, + {id: 0, type: 0, name: `Критерий №${prev.length + 1}`, maxPoints: 1} + ]); + setIsCriteriaOpen(true); + }; - const [metadata, setMetadata] = useState(undefined) + const updateCriterion = (index: number, patch: Partial) => + setCriteria(prev => + prev.map((c, i) => (i === index ? {...c, ...patch} : c)) + ) + + const removeCriterion = (index: number) => + setCriteria(prev => prev.filter((_, i) => i !== index)) + + const criteriaTotalPoints = useMemo( + () => + (criteria).reduce( + (sum, c) => sum + (c.maxPoints || 0), + 0 + ), + [criteria] + ) + + const autoMaxFromCriteria = criteria.length > 0; + + useEffect(() => { + if (autoMaxFromCriteria) setMaxRating(criteriaTotalPoints); + }, [criteriaTotalPoints, autoMaxFromCriteria]); + + const isNewTask = taskData.task.id! < 0 + + const [metadata, setMetadata] = useState( + isNewTask || taskData.isLoaded ? { + publicationDate: taskData.task.publicationDate, + hasDeadline: taskData.task.hasDeadline, + deadlineDate: taskData.task.deadlineDate, + isDeadlineStrict: taskData.task.isDeadlineStrict, + isPublished: taskData.task.isDeferred || !taskData.homework.isDeferred, + hasErrors: false, + } : undefined) useEffect(() => { + if (isNewTask || taskData.isLoaded) return ApiSingleton.tasksApi .tasksGetForEditingTask(task.id!) .then(r => { @@ -44,6 +119,7 @@ const CourseTaskEditor: FC<{ task: r.task!, isLoaded: true, }) + setCriteria(task.criteria || []) setMetadata({ hasDeadline: task.hasDeadline!, deadlineDate: task.deadlineDateNotSet @@ -53,18 +129,22 @@ const CourseTaskEditor: FC<{ publicationDate: task.publicationDateNotSet ? undefined : new Date(task.publicationDate!), - isPublished: !task.isDeferred - }); + isPublished: !task.isDeferred, + hasErrors: false, + }) }) }, []) const {task, homework, isLoaded} = taskData const {id} = task + //TODO: suggested max rating const [title, setTitle] = useState(task.title!) - const [maxRating, setMaxRating] = useState(task.maxRating!) + const [maxRating, setMaxRating] = useState( + criteria.length > 0 ? criteriaTotalPoints : task.maxRating! + ) const [description, setDescription] = useState(task.description!) - const [hasErrors, setHasErrors] = useState(false) + const [hasErrors, setHasErrors] = useState(props.speculativeTask.hasErrors || false) const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false) const [handleSubmitLoading, setHandleSubmitLoading] = useState(false); @@ -72,38 +152,71 @@ const CourseTaskEditor: FC<{ const publicationDate = metadata?.publicationDate || homework.publicationDate + useEffect(() => { + const update = { + ...props.speculativeTask, + ...metadata!, + title: title!, + description: description, + deadlineDateNotSet: metadata?.hasDeadline === true && !metadata.deadlineDate, + maxRating: maxRating, + hasErrors: hasErrors, + criteria: criteria, + }; + props.onUpdate({task: update}); + }, [title, description, maxRating, metadata, hasErrors, criteria]); + + useEffect(() => { + setHasErrors(!title || maxRating <= 0 || metadata?.hasErrors === true) + }, [title, maxRating, metadata?.hasErrors]) + const handleSubmit = async (e: any) => { e.preventDefault() setHandleSubmitLoading(true) - const updatedTask = await ApiSingleton.tasksApi.tasksUpdateTask(+id!, { + + const update = { ...metadata!, title: title!, description: description, maxRating: maxRating, actionOptions: editOptions, - }) + criteria: criteria, + }; - props.onUpdate(updatedTask.value!) + const updatedTask = isNewTask + ? await ApiSingleton.tasksApi.tasksAddTask(homework.id!, update) + : await ApiSingleton.tasksApi.tasksUpdateTask(+id!, update) + + if (isNewTask) + props.onUpdate({ + task: props.speculativeTask, + isDeleted: true, + }) + props.onUpdate({task: updatedTask.value!, isSaved: true}) } const deleteTask = async () => { - await ApiSingleton.tasksApi.tasksDeleteTask(id!) - props.onUpdate({...task, isDeleted: true}) + if (!isNewTask) await ApiSingleton.tasksApi.tasksDeleteTask(id!) + props.onUpdate({task, isDeleted: true}) } const isDisabled = hasErrors || !isLoaded + const isNewHomework = taskData.task.homeworkId! < 0 const homeworkPublicationDateIsSet = !homework.publicationDateNotSet + const maxRatingLabel = + criteria.length > 0 ? "Критерии" : props.speculativeTask.suggestedMaxRating === maxRating ? "Вычислено" : undefined + return ( - + alignItems={"center"} alignContent={"start"} style={{marginTop: -20}}> + 100} + helperText={maxRatingLabel} + style={{width: "90px"}} label="Баллы" variant="outlined" margin="normal" type="number" value={maxRating} + InputProps={{readOnly: autoMaxFromCriteria}} onChange={(e) => { - e.persist() - setMaxRating(+e.target.value) + if (!autoMaxFromCriteria) { + e.persist(); + setMaxRating(+e.target.value); + } }} /> @@ -158,9 +277,9 @@ const CourseTaskEditor: FC<{ isDeadlineStrict: state.isDeadlineStrict, publicationDate: state.publicationDate, deadlineDate: state.deadlineDate, - isPublished: metadata.isPublished, // Остается прежним + isPublished: metadata.isPublished, + hasErrors: state.hasErrors }) - setHasErrors(state.hasErrors) }} /> @@ -184,12 +303,137 @@ const CourseTaskEditor: FC<{ } + + {criteria.length === 0 && ( + + + + Критерии оценивания не указаны.  + + + + + Добавить критерий оценивания + + + + )} + {criteria.length > 0 && ( + <> + + + setIsCriteriaOpen(prev => !prev)} + > + {isCriteriaOpen ? ( + + ) : ( + + )} + + + + + + Критерии оценивания + + + + + + + {criteria.map((c, index) => ( + + + { + const raw = e.target.value; + const limited = raw.slice(0, 50); + updateCriterion(index, {name: limited}); + }} + /> + + + + { + if (e.key === "-") e.preventDefault(); + }} + onChange={(e) => + updateCriterion(index, { + maxPoints: Math.max(+e.target.value, 1), + }) + } + onBlur={(e) => + updateCriterion(index, { + maxPoints: Math.max(+e.target.value, 1), + }) + } + /> + + + removeCriterion(index)} + color={"error"} + size="small" + > + + + + + ))} + + + + + )} + - {publicationDate && new Date() >= new Date(publicationDate) && = new Date(publicationDate) && setEditOptions(value)}/>} - } loading={handleSubmitLoading} > - Редактировать задачу ({editOptions.sendNotification ? "с уведомлением" : "без уведомления"}) - + {isNewTask && "Добавить задачу"} + {!isNewTask && "Редактировать задачу " + (editOptions.sendNotification ? "с уведомлением" : "без уведомления")} + } setShowDeleteConfirmation(true)}> @@ -212,7 +457,7 @@ const CourseTaskEditor: FC<{ onSubmit={deleteTask} isOpen={showDeleteConfirmation} dialogTitle={'Удаление задачи'} - dialogContentText={`Вы точно хотите удалить задачу "${task.title}"?`} + dialogContentText={`Вы точно хотите удалить задачу '${title || ""}'?`} confirmationWord={''} confirmationText={''} /> @@ -221,13 +466,14 @@ const CourseTaskEditor: FC<{ } const CourseTaskExperimental: FC<{ - task: HomeworkTaskViewModel, + task: TaskEditData, homework: HomeworkViewModel, isMentor: boolean, initialEditMode: boolean, onMount: () => void, - onUpdate: (x: HomeworkTaskViewModel & { isDeleted?: boolean }) => void + onUpdate: (x: { task: TaskEditData, isDeleted?: boolean }) => void toEditHomework: () => void, + getAllHomeworks: () => HomeworkViewModel[], }> = (props) => { const {task, homework} = props const [showEditMode, setShowEditMode] = useState(false) @@ -240,47 +486,86 @@ const CourseTaskExperimental: FC<{ if (editMode) { return { - setEditMode(false) - props.onUpdate(update) + const updateFix = { + ...update, + task: { + ...update.task, + isModified: !update.isSaved, + } + } + props.onUpdate(updateFix) + if (update.isSaved) setEditMode(false) }} + getAllHomeworks={props.getAllHomeworks} toEditHomework={props.toEditHomework} /> } - return setShowEditMode(props.isMentor)} - onMouseLeave={() => setShowEditMode(false)}> - - - - - {task.title} - - - {task.isGroupWork && - - } - - {"⭐ " + task.maxRating} + return ( + setShowEditMode(props.isMentor)} + onMouseLeave={() => setShowEditMode(false)} + > + + + + + {task.title} + + + {task.isGroupWork && ( + + + + )} + + {"⭐ " + task.maxRating} + + {showEditMode && ( + + { + setShowEditMode(false); + setEditMode(true); + }} + > + + + + )} - {showEditMode && - { - setEditMode(true) - setShowEditMode(false) - }}> - - - } - - - - - - + + + + + + + + {task.criteria && task.criteria.length > 0 && ( + <> + + + + Критерии оценивания + + + + {task.criteria.map(c => ( + + {c.name} + + + ))} + + + )} + + ); } export default CourseTaskExperimental; \ No newline at end of file diff --git a/hwproj.front/src/components/Tasks/StudentStatsCell.tsx b/hwproj.front/src/components/Tasks/StudentStatsCell.tsx index 3ac2959e7..606496e3b 100644 --- a/hwproj.front/src/components/Tasks/StudentStatsCell.tsx +++ b/hwproj.front/src/components/Tasks/StudentStatsCell.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import {useState, FC, useEffect} from "react"; +import {FC} from "react"; import TableCell from "@material-ui/core/TableCell"; import {useNavigate} from "react-router-dom"; import {Solution} from "api"; @@ -7,6 +7,7 @@ import {Chip, Stack, Tooltip} from "@mui/material"; import StudentStatsUtils from "../../services/StudentStatsUtils"; import Utils from "../../services/Utils"; import {grey} from "@material-ui/core/colors"; +import "../Courses/Styles/StudentStatsCell.css"; interface ITaskStudentCellProps { studentId: string; @@ -14,6 +15,7 @@ interface ITaskStudentCellProps { forMentor: boolean; userId: string; taskMaxRating: number; + isBestSolution: boolean; solutions?: Solution[]; } @@ -27,7 +29,9 @@ const StudentStatsCell: FC const tooltipTitle = ratedSolutionsCount === 0 ? solutionsDescription - : solutionsDescription + `\n\n${Utils.pluralizeHelper(["Проверена", "Проверены", "Проверено"], ratedSolutionsCount)} ${ratedSolutionsCount} ${Utils.pluralizeHelper(["попытка", "попытки", "попыток"], ratedSolutionsCount)}`; + : solutionsDescription + + (props.isBestSolution ? "\n Первое решение с лучшей оценкой" : "") + + `\n\n${Utils.pluralizeHelper(["Проверена", "Проверены", "Проверено"], ratedSolutionsCount)} ${ratedSolutionsCount} ${Utils.pluralizeHelper(["попытка", "попытки", "попыток"], ratedSolutionsCount)}`; const result = cellState.lastRatedSolution === undefined ? "" @@ -36,13 +40,29 @@ const StudentStatsCell: FC ; + const handleCellClick = (e: React.MouseEvent) => { + // Формируем URL + const url = forMentor + ? `/task/${props.taskId}/${props.studentId}` + : `/task/${props.taskId}` + // Проверяем, была ли нажата Ctrl/Cmd + const isSpecialClick = e.ctrlKey || e.metaKey; + + if (isSpecialClick) { + // Открываем в новой вкладке + window.open(url, '_blank', 'noopener,noreferrer'); + } else { + // Переходим в текущей вкладке + navigate(url); + } + }; + return ( - {tooltipTitle}}> forMentor - ? navigate(`/task/${props.taskId}/${props.studentId}`) - : navigate(`/task/${props.taskId}`)} + onClick={handleCellClick} + className={props.isBestSolution ? "glow-cell" : ""} component="td" padding="none" variant={"body"} diff --git a/hwproj.front/src/components/Tasks/TaskDeadlines.tsx b/hwproj.front/src/components/Tasks/TaskDeadlines.tsx index 8419738cf..1ddbcbf62 100644 --- a/hwproj.front/src/components/Tasks/TaskDeadlines.tsx +++ b/hwproj.front/src/components/Tasks/TaskDeadlines.tsx @@ -65,12 +65,6 @@ const TaskDeadlines: FC = ({taskDeadlines, onGiveUpClick}) - {(solutionState == null) && - - - - } {!deadlinePast && ( {renderBadge(solutionState, rating!, deadline!.maxRating!)} diff --git a/hwproj.front/src/components/Tasks/TaskQuestions.tsx b/hwproj.front/src/components/Tasks/TaskQuestions.tsx index ab28c2b49..bff6427ac 100644 --- a/hwproj.front/src/components/Tasks/TaskQuestions.tsx +++ b/hwproj.front/src/components/Tasks/TaskQuestions.tsx @@ -11,19 +11,21 @@ import { Typography } from "@mui/material"; import * as React from "react"; +import ArrowOutwardIcon from '@mui/icons-material/ArrowOutward'; import {MarkdownEditor, MarkdownPreview} from "../Common/MarkdownEditor"; import Button from "@material-ui/core/Button"; import ApiSingleton from "../../api/ApiSingleton"; -import {AccountDataDto, AddAnswerForQuestionDto, AddTaskQuestionDto, GetTaskQuestionDto} from "../../api"; +import {AccountDataDto, AddAnswerForQuestionDto, AddTaskQuestionDto, GetTaskQuestionDto} from "@/api"; import {Checkbox} from "@mui/material/"; import CloseIcon from "@mui/icons-material/Close"; import GroupsIcon from "@mui/icons-material/Groups"; import PersonIcon from "@mui/icons-material/Person"; import AvatarUtils from "../Utils/AvatarUtils"; +import {Link as ReactLink} from "react-router-dom"; interface ITaskQuestionsProps { forMentor: boolean - student: AccountDataDto + courseStudents: AccountDataDto[] taskId: number questions: GetTaskQuestionDto[] onChange: () => void @@ -131,12 +133,12 @@ const TaskQuestions: FC = (props) => { } {props.questions.map(q => { const addAnswer = q.id === addAnswerState.questionId - const isCurrentStudent = q.studentId === props.student.userId + const student = props.courseStudents.find(s => s.userId === q.studentId) const isAnswered = q.answer !== null return + icon={student !== undefined + ? : q.isPrivate ? : } @@ -166,9 +168,15 @@ const TaskQuestions: FC = (props) => { }> - {isCurrentStudent && - Вопрос от проверяемого студента: - } + {props.forMentor && student && + + + {student.surname + " " + student.name} + + + + } {!isAnswered && q.id === addAnswerState.questionId && { + static async getErrorMessages(response: Response, expectedJsonField?: string): Promise { try { const contentType = response.headers.get("Content-Type"); - if (contentType?.includes("application/json")) { - return await response.json(); + var errorJson = await response.json(); + return expectedJsonField ? + errorJson[expectedJsonField] ?? errorJson + : errorJson } else { return [await response.text()]; } diff --git a/hwproj.front/src/components/Utils/FileInfoConverter.ts b/hwproj.front/src/components/Utils/FileInfoConverter.ts index d7ea04880..4da4db13d 100644 --- a/hwproj.front/src/components/Utils/FileInfoConverter.ts +++ b/hwproj.front/src/components/Utils/FileInfoConverter.ts @@ -1,29 +1,34 @@ import {IFileInfo} from "components/Files/IFileInfo"; -import {FileInfoDTO} from "../../api" +import {FileInfoDTO} from "@/api" +import { CourseUnitType } from "../Files/CourseUnitType"; +import { FileStatus } from "../Files/FileStatus"; export default class FileInfoConverter { public static fromFileInfoDTO(fileInfoDto: FileInfoDTO): IFileInfo { if (fileInfoDto.name === undefined - || fileInfoDto.size === undefined - || fileInfoDto.key === undefined - || fileInfoDto.homeworkId === undefined) { + || fileInfoDto.status === undefined + || fileInfoDto.sizeInBytes === undefined) { throw new Error("Обнаружено пустое поле объекта FileInfoDTO") } return { + id: fileInfoDto.id, + status: fileInfoDto.status as FileStatus, name: fileInfoDto.name, - sizeInBytes: fileInfoDto.size, - key: fileInfoDto.key + sizeInBytes: fileInfoDto.sizeInBytes, + courseUnitType: fileInfoDto.courseUnitType as CourseUnitType, + courseUnitId: fileInfoDto.courseUnitId! }; } - + public static fromFileInfoDTOArray(fileInfoDtos: FileInfoDTO[]): IFileInfo[] { return fileInfoDtos.map(fileInfoDto => this.fromFileInfoDTO(fileInfoDto)); } - public static getHomeworkFilesInfo(filesInfo: FileInfoDTO[], homeworkId: number): IFileInfo[] { + public static getCourseUnitFilesInfo(filesInfo: FileInfoDTO[], courseUnitType: CourseUnitType, courseUnitId: number): IFileInfo[] { return FileInfoConverter.fromFileInfoDTOArray( - filesInfo.filter(filesInfo => filesInfo.homeworkId === homeworkId) + filesInfo.filter(filesInfo => filesInfo.courseUnitType === courseUnitType + && filesInfo.courseUnitId === courseUnitId) ) } } \ No newline at end of file diff --git a/hwproj.front/src/components/Utils/ProcessFilesUtils.ts b/hwproj.front/src/components/Utils/ProcessFilesUtils.ts new file mode 100644 index 000000000..0a7c685f1 --- /dev/null +++ b/hwproj.front/src/components/Utils/ProcessFilesUtils.ts @@ -0,0 +1,20 @@ +import ApiSingleton from "api/ApiSingleton"; +import { enqueueSnackbar } from "notistack"; +import ErrorsHandler from "./ErrorsHandler"; +import { IProcessFilesDto } from "../Files/IProcessFilesDto"; + +export default class ProcessFilesUtils { + public static async processFilesWithErrorsHadling(processFilesDto: IProcessFilesDto) { + try { + await ApiSingleton.customFilesApi.processFiles(processFilesDto); + } catch (e) { + const errors = await ErrorsHandler.getErrorMessages(e as Response); + var errorDescription = errors[0] == undefined ? `` : `${errors[0]}` + if (errorDescription.length > 300) errorDescription = `` + enqueueSnackbar(`Проблема при обработке файлов ${errorDescription}`, { + variant: "warning", + autoHideDuration: 2000 + }); + } + } +} \ No newline at end of file diff --git a/hwproj.front/src/components/Workspace.tsx b/hwproj.front/src/components/Workspace.tsx index 722cde380..82d5877a4 100644 --- a/hwproj.front/src/components/Workspace.tsx +++ b/hwproj.front/src/components/Workspace.tsx @@ -1,14 +1,13 @@ import * as React from "react"; -import {Typography, Grid, Tabs, Tab} from "@material-ui/core"; +import {Tabs, Tab} from "@material-ui/core"; import ApiSingleton from "api/ApiSingleton"; -import {UnratedSolutionPreviews, UserDataDto} from "../api/"; +import {UnratedSolutionPreviews, UserDataDto} from "@/api"; import "./Styles/Profile.css"; import {FC, useEffect, useState} from "react"; import {Link, useParams} from "react-router-dom"; -import {makeStyles} from "@material-ui/styles"; import TaskDeadlines from "./Tasks/TaskDeadlines"; -import UnratedSolutions from "./Solutions/UnratedSolutions"; -import {Alert, Chip, Stack} from "@mui/material"; +import UnratedSolutionsAndOpenQuestions from "./Solutions/UnratedSolutionsAndOpenQuestions"; +import {Alert, Chip, Grid, Stack, Typography} from "@mui/material"; import NewCourseEvents from "./Courses/NewCourseEvents"; import {TestTag} from "./Common/HomeworkTags"; import Utils from "../services/Utils"; @@ -20,12 +19,6 @@ interface IWorkspaceState { tabValue: number; } -const useStyles = makeStyles(() => ({ - info: { - justifyContent: "space-between", - }, -})) - const Workspace: FC = () => { const {id} = useParams() @@ -41,7 +34,6 @@ const Workspace: FC = () => { unratedSolutionPreviews: undefined }) - const classes = useStyles() const isLecturer = ApiSingleton.authService.isLecturer() const isExpert = ApiSingleton.authService.isExpert() const isMentor = isLecturer || isExpert @@ -99,9 +91,9 @@ const Workspace: FC = () => { return (
- - - + + + {fullName} @@ -134,7 +126,6 @@ const Workspace: FC = () => { variant="scrollable" scrollButtons={"auto"} value={tabValue} - style={{marginTop: 10}} indicatorColor="primary" onChange={(event, value) => { setProfileState(prevState => ({ @@ -176,7 +167,7 @@ const Workspace: FC = () => {
{tabValue === 0 && (isMentor - ? + ? : )} {tabValue === 1 && !isExpert && @@ -186,7 +177,7 @@ const Workspace: FC = () => { onGiveUpClick={onGiveUpClick}/>)}
} - + localStorage.clear(); - getProfile = () => decode(this.getToken() as string); + getProfile = () => { + let result = decode(this.getToken() as string); + if (result.exp < 1761527002) { + this.logout() + alert("Мы обновили кое-что важное, и чтобы все правильно работало, просим вас заново войти в аккаунт! Приносим извинения за неудобства.") + window.location.reload() + } + return result + }; getUserId = () => this.getProfile()._id; diff --git a/hwproj.front/src/services/Utils.ts b/hwproj.front/src/services/Utils.ts index 221de2fc1..d0a718c76 100644 --- a/hwproj.front/src/services/Utils.ts +++ b/hwproj.front/src/services/Utils.ts @@ -27,7 +27,11 @@ export default class Utils { if (diffHoursInt === 0) { const diffMinutes = Math.trunc(milliseconds / (1000 * 60)) - return diffMinutes + " " + this.pluralizeHelper(["минуту", "минуты", "минут"], diffMinutes) + if (diffMinutes > 0) { + return diffMinutes + " " + this.pluralizeHelper(["минуту", "минуты", "минут"], diffMinutes) + } + const diffSeconds = Math.trunc(milliseconds / 1000) + return diffSeconds + " " + this.pluralizeHelper(["секунду", "секунды", "секунд"], diffSeconds) } const diffDays = Math.trunc(diffHours / 24) @@ -70,7 +74,7 @@ export default class Utils { month: 'long', day: 'numeric', }; - + return (new Date(date)).toLocaleString(undefined, options) } diff --git a/hwproj.front/vite.config.ts b/hwproj.front/vite.config.ts index 72b7a3bca..a5740710f 100644 --- a/hwproj.front/vite.config.ts +++ b/hwproj.front/vite.config.ts @@ -36,7 +36,8 @@ export default defineConfig({ host: 'localhost', port: 3000, protocol: 'wss' - } + }, + open: true }, build: { outDir: "dist", diff --git a/restore_from_backup.sh b/restore_from_backup.sh new file mode 100644 index 000000000..587d8df0c --- /dev/null +++ b/restore_from_backup.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +# Загрузка переменных из .env +set -a # Экспортируем все переменные, пропуская комментарии и пустые строки +source <(grep -v '^\s*#' ./.env | grep -v '^\s*$') || { echo "Не удалось загрузить .env файл!" >&2; exit 1; } +set +a # Останавливаем экспорт переменных + +# Проверка, загружены ли необходимые переменные окружения +REQUIRED_VARS=("MSSQL_SA_PASSWORD" "MSSQL_BACKUPS_VOLUME" "BACKUPS_STORAGE") +for VAR in "${REQUIRED_VARS[@]}"; do + [[ -z "${!VAR}" ]] && { echo "Ошибка: $VAR не задана в .env!" >&2; exit 1; } +done + +# Задаем другие необходимые переменные +CONTAINER_NAME="mssqllocaldb" +#ARCHIVE_NAME="backup_$TIMESTAMP.tar.gz" + +# Задайте требуемое архива ARCHIVE_NAME и удалите строку exit 1; +exit 1; +# Задайте требуемое архива ARCHIVE_NAME и удалите строку exit 1; + +TZ="Europe/Moscow" +TIMESTAMP=$(TZ=$TZ date +"%d%m%Y-%H%M%S") # Формат: ДДММГГГГ-ЧЧММСС +TMP_DIR="$BACKUPS_STORAGE/tmp_extract_$TIMESTAMP" + +# Создаем временную директорию для извлечения из архива +mkdir -p $TMP_DIR || { echo "[ERROR] Не удалось создать $TMP_DIR" >&2; exit 1; } + +# Достаем из архива все bak-файлы и копируем в volume бэкапов ms sql +tar -xzvf "$BACKUPS_STORAGE/$ARCHIVE_NAME" -C "$TMP_DIR" +cp $TMP_DIR/*.bak "$MSSQL_BACKUPS_VOLUME" + +# Выполняем восстановление каждой базы данных +for BACKUP_FILE in $MSSQL_BACKUPS_VOLUME/*.bak; do + # Получаем только имя файла без пути + BACKUP_FILE_NAME=$(basename "$BACKUP_FILE") + # Получаем название базы данных из имени файла + DB_NAME=$(basename "$BACKUP_FILE" .bak) + + # Перевод БД в однопользовательский режим для обеспечения эксклюзивного доступа + echo -e "\nГотовим базу $DB_NAME к восстановлению" + docker exec -it "$CONTAINER_NAME" /opt/mssql-tools18/bin/sqlcmd -S localhost -U SA -P "$MSSQL_SA_PASSWORD" -C \ + -Q "ALTER DATABASE [$DB_NAME] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;" + + echo "Начинаем восстановление $DB_NAME из файла $BACKUP_FILE_NAME" + docker exec -it "$CONTAINER_NAME" /opt/mssql-tools18/bin/sqlcmd -S localhost -U SA -P "$MSSQL_SA_PASSWORD" -C \ + -Q "RESTORE DATABASE [$DB_NAME] FROM DISK = '/var/opt/mssql/backups/$BACKUP_FILE_NAME' \ + WITH MOVE '${DB_NAME}' TO '/var/opt/mssql/data/$DB_NAME.mdf', \ + MOVE '${DB_NAME}_log' TO '/var/opt/mssql/data/${DB_NAME}_log.ldf', \ + REPLACE;" + + # Возвращаем БД в многопользовательский режим + docker exec -it "$CONTAINER_NAME" /opt/mssql-tools18/bin/sqlcmd -S localhost -U SA -P "$MSSQL_SA_PASSWORD" -C \ + -Q "ALTER DATABASE [$DB_NAME] SET MULTI_USER;" + + # Проверка успешности выполнения + if [ $? -eq 0 ]; then + echo -e "\n[$(TZ=$TZ date)] БД $DB_NAME успешно восстановлена" >> /var/log/mssql_backup.log + else + echo "[$(TZ=$TZ date)] Ошибка восстановления БД $DB_NAME !" >> /var/log/mssql_backup_error.log + exit 1 + fi +done + +# Удаляем временную папку с бэкапами и очищаем volume бэкапов +echo -e "\nОчищаем временные ресурсы" +rm -rf $TMP_DIR +rm -rf $MSSQL_BACKUPS_VOLUME/* + +echo -e "\n[SUCCESS] Все БД успешно восстановлены из бэкапа $BACKUPS_STORAGE/$ARCHIVE_NAME" \ No newline at end of file diff --git a/send_to_yadisk.sh b/send_to_yadisk.sh new file mode 100644 index 000000000..b03850808 --- /dev/null +++ b/send_to_yadisk.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# Принимаем название файла из параметра +FILE_NAME="$1" + +# Проверяем имя файла на непустоту +if [ -z "$FILE_NAME" ]; then + echo "Ошибка: имя выгружаемого файла не передано в виде параметра" + exit 1 +fi + +echo "Имя выгружаемого файла: $FILE_NAME" + +REMOTE_DIR="mssql_backups" # Папка на Яндекс.Диске + +# Загружаем файл через rclone +rclone copy "$FILE_NAME" yadisk:"$REMOTE_DIR" \ + --log-file="/var/log/yadisk_upload.log" \ + --stats=1s \ + --retries 3; From 4a15e970dc6d5bc236d6e5c3aa99a806c506a6e1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 00:11:10 +0000 Subject: [PATCH 3/4] Fix build errors after merge: update Course model and fix CoursesService Co-authored-by: DedSec256 <26364714+DedSec256@users.noreply.github.com> --- .../AuthService/ViewModels/User.cs | 25 ------------------- .../HwProj.Repositories/CrudRepository.cs | 2 +- .../Models/Course.cs | 2 +- .../Services/CoursesService.cs | 6 ++--- 4 files changed, 4 insertions(+), 31 deletions(-) delete mode 100644 HwProj.Common/HwProj.Models/AuthService/ViewModels/User.cs diff --git a/HwProj.Common/HwProj.Models/AuthService/ViewModels/User.cs b/HwProj.Common/HwProj.Models/AuthService/ViewModels/User.cs deleted file mode 100644 index 5f5c599e8..000000000 --- a/HwProj.Common/HwProj.Models/AuthService/ViewModels/User.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Microsoft.AspNetCore.Identity; - -namespace HwProj.Models.AuthService.ViewModels -{ - public class User : IdentityUser - { - public string GitHubId { get; set; } - - public string Name { get; set; } - - public string Surname { get; set; } - - public string MiddleName { get; set; } - - public bool IsExternalAuth { get; set; } - - public string Bio { get; set; } - - public string CompanyName { get; set; } - - public User() - { - } - } -} diff --git a/HwProj.Common/HwProj.Repositories/CrudRepository.cs b/HwProj.Common/HwProj.Repositories/CrudRepository.cs index ea23293b2..32b31c016 100644 --- a/HwProj.Common/HwProj.Repositories/CrudRepository.cs +++ b/HwProj.Common/HwProj.Repositories/CrudRepository.cs @@ -9,7 +9,7 @@ namespace HwProj.Repositories { public class CrudRepository : ReadOnlyRepository, ICrudRepository - where TEntity : class, IEntity + where TEntity : class, IEntity, new() where TKey : IEquatable { public CrudRepository(DbContext context) diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Models/Course.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Models/Course.cs index e5f6af8a3..695ec6287 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Models/Course.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Models/Course.cs @@ -12,7 +12,7 @@ public class Course : IEntity public bool IsOpen { get; set; } public string InviteCode { get; set; } public bool IsCompleted { get; set; } - public string MentorIds { get; set; } + public List Mentors { get; set; } = new List(); public List CourseMates { get; set; } = new List(); public List Homeworks { get; set; } = new List(); public List Assignments { get; set; } = new List(); diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Services/CoursesService.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Services/CoursesService.cs index 026e401f9..09a27e384 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Services/CoursesService.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Services/CoursesService.cs @@ -370,11 +370,9 @@ public async Task GetLecturersAvailableForCourse(long courseId { var lecturers = await _authServiceClient.GetAllLecturers(); var mentorIds = await GetCourseLecturers(courseId); - var availableLecturers = lecturers.Where(u => !mentorIds.Contains(u.Id)); + var availableLecturers = lecturers.Where(u => !mentorIds.Contains(u.UserId)); - return availableLecturers - .Select(u => u.ToAccountDataDto(Roles.LecturerRole)) - .ToArray(); + return availableLecturers.ToArray(); } } } From 0c51405f3905ef31cb7562f70f6ccc76fbe70c75 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 00:16:38 +0000 Subject: [PATCH 4/4] Security: Update axios from 0.30.2 to 1.13.5 to fix DoS vulnerabilities Co-authored-by: DedSec256 <26364714+DedSec256@users.noreply.github.com> --- hwproj.front/package-lock.json | 107 ++++++++++++++------------------- hwproj.front/package.json | 2 +- 2 files changed, 47 insertions(+), 62 deletions(-) diff --git a/hwproj.front/package-lock.json b/hwproj.front/package-lock.json index a0882868d..c26cba420 100644 --- a/hwproj.front/package-lock.json +++ b/hwproj.front/package-lock.json @@ -32,7 +32,7 @@ "@uiw/react-md-editor": "3.25.6", "avatarka": "^1.0.1", "avatarka-react": "^1.0.1", - "axios": "^0.30.2", + "axios": "^1.13.5", "bootstrap": "^4.3.1", "classnames": "^2.3.1", "color-util": "^2.2.3", @@ -4977,6 +4977,7 @@ "version": "6.5.16", "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.5.16.tgz", "integrity": "sha512-p3DqQi+8QRL5k7jXhXmJZLsE/GqHqyY6PcoA1oNTJr0try48uhTGUOYkgzmqtDaa/qPFO5LP+xCPzZXckGtquQ==", + "dev": true, "license": "MIT", "dependencies": { "@storybook/api": "6.5.16", @@ -5004,12 +5005,14 @@ "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true, "license": "MIT" }, "node_modules/@storybook/api": { "version": "6.5.16", "resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.5.16.tgz", "integrity": "sha512-HOsuT8iomqeTMQJrRx5U8nsC7lJTwRr1DhdD0SzlqL4c80S/7uuCy4IZvOt4sYQjOzW5fOo/kamcoBXyLproTA==", + "dev": true, "license": "MIT", "dependencies": { "@storybook/channels": "6.5.16", @@ -5043,6 +5046,7 @@ "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true, "license": "MIT" }, "node_modules/@storybook/builder-webpack4": { @@ -5441,6 +5445,7 @@ "version": "6.5.16", "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.5.16.tgz", "integrity": "sha512-VylzaWQZaMozEwZPJdyJoz+0jpDa8GRyaqu9TGG6QGv+KU5POoZaGLDkRE7TzWkyyP0KQLo80K99MssZCpgSeg==", + "dev": true, "license": "MIT", "dependencies": { "core-js": "^3.8.2", @@ -5500,6 +5505,7 @@ "version": "6.5.16", "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.5.16.tgz", "integrity": "sha512-pxcNaCj3ItDdicPTXTtmYJE3YC1SjxFrBmHcyrN+nffeNyiMuViJdOOZzzzucTUG0wcOOX8jaSyak+nnHg5H1Q==", + "dev": true, "license": "MIT", "dependencies": { "core-js": "^3.8.2", @@ -5514,6 +5520,7 @@ "version": "6.5.16", "resolved": "https://registry.npmjs.org/@storybook/components/-/components-6.5.16.tgz", "integrity": "sha512-LzBOFJKITLtDcbW9jXl0/PaG+4xAz25PK8JxPZpIALbmOpYWOAPcO6V9C2heX6e6NgWFMUxjplkULEk9RCQMNA==", + "dev": true, "license": "MIT", "dependencies": { "@storybook/client-logger": "6.5.16", @@ -5538,6 +5545,7 @@ "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true, "license": "MIT" }, "node_modules/@storybook/core": { @@ -5704,6 +5712,7 @@ "version": "6.5.16", "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.5.16.tgz", "integrity": "sha512-qMZQwmvzpH5F2uwNUllTPg6eZXr2OaYZQRRN8VZJiuorZzDNdAFmiVWMWdkThwmyLEJuQKXxqCL8lMj/7PPM+g==", + "dev": true, "license": "MIT", "dependencies": { "core-js": "^3.8.2" @@ -5804,6 +5813,7 @@ "version": "0.0.2--canary.4566f4d.1", "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.2--canary.4566f4d.1.tgz", "integrity": "sha512-9OVvMVh3t9znYZwb0Svf/YQoxX2gVOeQTGe2bses2yj+a3+OJnCrUF3/hGv6Em7KujtOdL2LL+JnG49oMVGFgQ==", + "dev": true, "license": "MIT", "dependencies": { "lodash": "^4.17.15" @@ -6276,6 +6286,7 @@ "version": "6.5.16", "resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.5.16.tgz", "integrity": "sha512-ZgeP8a5YV/iuKbv31V8DjPxlV4AzorRiR8OuSt/KqaiYXNXlOoQDz/qMmiNcrshrfLpmkzoq7fSo4T8lWo2UwQ==", + "dev": true, "license": "MIT", "dependencies": { "@storybook/client-logger": "6.5.16", @@ -6297,12 +6308,14 @@ "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true, "license": "MIT" }, "node_modules/@storybook/semver": { "version": "7.3.2", "resolved": "https://registry.npmjs.org/@storybook/semver/-/semver-7.3.2.tgz", "integrity": "sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg==", + "dev": true, "license": "ISC", "dependencies": { "core-js": "^3.6.5", @@ -6319,6 +6332,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -6332,6 +6346,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -6344,6 +6359,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -6359,6 +6375,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -6442,6 +6459,7 @@ "version": "6.5.16", "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.5.16.tgz", "integrity": "sha512-hNLctkjaYLRdk1+xYTkC1mg4dYz2wSv6SqbLpcKMbkPHTE0ElhddGPHQqB362md/w9emYXNkt1LSMD8Xk9JzVQ==", + "dev": true, "license": "MIT", "dependencies": { "@storybook/client-logger": "6.5.16", @@ -6462,6 +6480,7 @@ "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true, "license": "MIT" }, "node_modules/@storybook/ui": { @@ -7088,6 +7107,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/@types/is-function/-/is-function-1.0.3.tgz", "integrity": "sha512-/CLhCW79JUeLKznI6mbVieGbl4QU5Hfn+6udw1YHZoofASjbQ5zaP5LzAUZYDpRYEjS4/P+DhEgyJ/PQmGGTWw==", + "dev": true, "license": "MIT" }, "node_modules/@types/isomorphic-fetch": { @@ -7456,6 +7476,7 @@ "version": "1.18.8", "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.8.tgz", "integrity": "sha512-G9eAoJRMLjcvN4I08wB5I7YofOb/kaJNd5uoCMX+LbKXTPCF+ZIHuqTnFaK9Jz1rgs035f9JUPUhNFtqgucy/A==", + "dev": true, "license": "MIT" }, "node_modules/@types/webpack-sources": { @@ -9642,13 +9663,13 @@ } }, "node_modules/axios": { - "version": "0.30.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.30.2.tgz", - "integrity": "sha512-0pE4RQ4UQi1jKY6p7u6i1Tkzqmu+d+/tHS7Q7rKunWLB9WyilBTpHHpXzPNMDj5hTbK0B0PTLSz07yqMBiF6xg==", + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", + "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.4", - "form-data": "^4.0.4", + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, @@ -15005,9 +15026,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "funding": [ { "type": "individual", @@ -15188,9 +15209,9 @@ } }, "node_modules/form-data": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -18027,6 +18048,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true, "license": "MIT" }, "node_modules/is-generator-function": { @@ -18149,6 +18171,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -18226,6 +18249,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -18697,13 +18721,6 @@ "node": ">= 10.13.0" } }, - "node_modules/jquery": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", - "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", - "license": "MIT", - "peer": true - }, "node_modules/js-sha3": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", @@ -19343,6 +19360,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", "integrity": "sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==", + "dev": true, "license": "MIT" }, "node_modules/map-visit": { @@ -20535,6 +20553,7 @@ "version": "1.11.3", "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", "integrity": "sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==", + "dev": true, "license": "MIT", "dependencies": { "map-or-similar": "^1.5.0" @@ -20591,21 +20610,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/meow": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", - "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/merge-descriptors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", @@ -22516,6 +22520,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -22718,6 +22723,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -22870,18 +22876,6 @@ "node": ">=6" } }, - "node_modules/popper.js": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", - "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", - "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1", - "license": "MIT", - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, "node_modules/portable-fetch": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/portable-fetch/-/portable-fetch-3.0.0.tgz", @@ -27176,6 +27170,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -28052,6 +28047,7 @@ "version": "2.14.4", "resolved": "https://registry.npmjs.org/store2/-/store2-2.14.4.tgz", "integrity": "sha512-srTItn1GOvyvOycgxjAnPA63FZNwy0PTyUBFMHRM+hVFltAeoh0LmNBz9SZqUS9mMqGk8rfyWyXn3GH5ReJ8Zw==", + "dev": true, "license": "MIT" }, "node_modules/stream-browserify": { @@ -28685,6 +28681,7 @@ "version": "6.0.8", "resolved": "https://registry.npmjs.org/telejson/-/telejson-6.0.8.tgz", "integrity": "sha512-nerNXi+j8NK1QEfBHtZUN/aLdDcyupA//9kAboYLrtzZlPLpUfqbVGWb9zz91f/mIjRbAYhbgtnJHY8I1b5MBg==", + "dev": true, "license": "MIT", "dependencies": { "@types/is-function": "^1.0.0", @@ -28701,6 +28698,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -29222,6 +29220,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.10" @@ -30114,6 +30113,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, "license": "MIT" }, "node_modules/util.promisify": { @@ -31969,21 +31969,6 @@ "dev": true, "license": "ISC" }, - "node_modules/yaml": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", - "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", diff --git a/hwproj.front/package.json b/hwproj.front/package.json index 0ddb05582..3ecf9c04e 100644 --- a/hwproj.front/package.json +++ b/hwproj.front/package.json @@ -28,7 +28,7 @@ "@uiw/react-md-editor": "3.25.6", "avatarka": "^1.0.1", "avatarka-react": "^1.0.1", - "axios": "^0.30.2", + "axios": "^1.13.5", "bootstrap": "^4.3.1", "classnames": "^2.3.1", "color-util": "^2.2.3",